Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 287
Functions: 0.0% 0 / 0 / 16
Branches: 0.0% 0 / 0 / 289

OMCompiler/SimulationRuntime/c/simulation/modelinfo.c
Line Branch Exec Source
1 /*
2 * This file belongs to the OpenModelica Run-Time System
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), c/o Linköpings
5 * universitet, Department of Computer and Information Science, SE-58183 Linköping, Sweden. All rights
6 * reserved.
7 *
8 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE
9 * AGPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. ANY
10 * USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S
11 * ACCEPTANCE OF THE BSD NEW LICENSE OR THE OSMC PUBLIC LICENSE OR THE AGPL
12 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
13 *
14 * The OpenModelica software and the OSMC (Open Source Modelica Consortium) Public License
15 * (OSMC-PL) are obtained from OSMC, either from the above address, from the URLs:
16 * http://www.openmodelica.org or https://github.com/OpenModelica/ or
17 * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica distribution. GNU
18 * AGPL version 3 is obtained from: https://www.gnu.org/licenses/licenses.html#GPL. The BSD NEW
19 * License is obtained from: http://www.opensource.org/licenses/BSD-3-Clause.
20 *
21 * This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY
23 * SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF
24 * OSMC-PL.
25 *
26 */
27
28 #include "../util/omc_error.h"
29 #include "../simulation_data.h"
30 #include "../util/rtclock.h"
31 #include "modelinfo.h"
32 #include "simulation_info_json.h"
33 #include "simulation_runtime.h"
34 #include "../util/omc_mmap.h"
35 #include "../util/omc_strdup.h"
36 #include "solver/model_help.h"
37
38
39 #include <errno.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <time.h>
43 #include <assert.h>
44 #include <stdint.h>
45 #include "../util/read_matlab4.h"
46 #include "../util/omc_file.h"
47
48 /* UNDEF to debug the gnuplot file */
49 #define NO_PIPE
50
51 /* Returns -1 if the file was not found */
52 ✗ static size_t fileSize(const char *filename) {
53 size_t sz = -1;
54 ✗ FILE *f = omc_fopen(filename, "rb");
55 ✗ if(f) {
56 ✗ fseek(f, 0, SEEK_END);
57 ✗ sz = ftell(f);
58 ✗ fclose(f);
59 }
60 ✗ return sz;
61 }
62
63 static void indent(FILE *fout, int n) {
64 ✗ while(n--) fputc(' ', fout);
65 }
66
67 ✗ static void convertProfileData(const char *outputPath, const char *prefix, int numFnsAndBlocks)
68 {
69 const char* fullFileName;
70 ✗ if (0 > GC_asprintf(&fullFileName, "%s%s", outputPath, prefix)) {
71 ✗ throwStreamPrint(NULL, "modelinfo.c: Error: can not allocate memory.");
72 }
73 ✗ size_t len = strlen(fullFileName);
74 ✗ char *inBinaryInt = (char*)malloc(sizeof(char)*(len + 14));
75 ✗ char *inBinaryReal = (char*)malloc(sizeof(char)*(len + 15));
76 FILE *finInt, *finReal, *fout;
77 int fail = 0;
78 ✗ size_t intRowSize = sizeof(uint32_t)*(1+numFnsAndBlocks);
79 ✗ size_t realRowSize = sizeof(double)*(2+numFnsAndBlocks);
80 uint32_t *intData;
81 double *realData;
82 /* There seems to be a very small performance gain from using mmap here.
83 * But it is not worse than in-memory and may be paged out on low memory. */
84 omc_mmap_write intMap,realMap;
85
86 memcpy(inBinaryInt,fullFileName,len);
87 memcpy(inBinaryReal,fullFileName,len);
88 ✗ strcpy(inBinaryInt + len, "_prof.intdata");
89 ✗ strcpy(inBinaryReal + len, "_prof.realdata");
90
91 ✗ intMap = omc_mmap_open_write(inBinaryInt,0);
92 ✗ intData = (uint32_t*)intMap.data;
93 ✗ assert(0 == intMap.size % intRowSize);
94 ✗ matrix_transpose_uint32(intData, 1+numFnsAndBlocks, intMap.size / intRowSize);
95 ✗ omc_mmap_close_write(intMap);
96
97 ✗ realMap = omc_mmap_open_write(inBinaryReal,0);
98 ✗ realData = (double*)realMap.data;
99 ✗ assert(0 == realMap.size % realRowSize);
100 ✗ matrix_transpose(realData, 2+numFnsAndBlocks, realMap.size / realRowSize);
101 ✗ omc_mmap_close_write(realMap);
102
103 ✗ free(inBinaryInt);
104 ✗ free(inBinaryReal);
105 ✗ }
106
107 ✗ static void printPlotCommand(FILE *plt, const char *plotFormat, const char *title, const char *outputPath, const char *prefix, int numFnsAndBlocks, int i, int id, const char *idPrefix) {
108 const char *format = "plot \"%s%s_prof.realdata\" binary format=\"%%%ddouble\" using 1:($%d>1e-9 ? $%d : 1e-30) w l lw %d\n";
109 const char *formatCount = "plot \"%s%s_prof.intdata\" binary format=\"%%%duint32\" using %d w l lw %d\n";
110 unsigned long nmin = 0, nmax = 0;
111 double ymin = 0.0, ymax = 0.0;
112 double ygraphmin = 1e-30, ygraphmax = 0.0;
113 ✗ if(!plt) return;
114 ✗ if(i >= 0) {
115 /*
116 * Note: We set the yrange here because otherwise we get warnings if the
117 * number of calls are the same in every time step (i.e. autoscale thinks
118 * the range is [3:3])
119 */
120 ✗ nmin = rt_ncall_min(SIM_TIMER_FIRST_FUNCTION + i);
121 ✗ nmax = rt_ncall_max(SIM_TIMER_FIRST_FUNCTION + i);
122 ✗ ymin = nmin==0 ? -0.01 : nmin*0.95;
123 ✗ ymax = nmax==0 ? 0.01 : nmax*1.05;
124 ✗ ygraphmax = rt_max_accumulated(SIM_TIMER_FIRST_FUNCTION + i) * 1.01 + 1e-30;
125 }
126 /* SVG thumbnail */
127 ✗ fputs("set terminal svg\n", plt);
128 fprintf(plt, "unset xtics\n");
129 fprintf(plt, "unset ytics\n");
130 fprintf(plt, "unset border\n");
131 fprintf(plt, "set output \"%s%s_prof.%s%d.thumb.svg\"\n", outputPath, prefix, idPrefix, id);
132 fprintf(plt, "set title\n");
133 fprintf(plt, "set xlabel\n");
134 fprintf(plt, "set ylabel\n");
135 fprintf(plt, "set log y\n");
136
137 ✗ if(i>=0)
138 {
139 fprintf(plt, "set yrange [*:%g]\n", ygraphmax);
140 }
141 else
142 {
143 fprintf(plt, "set yrange [*:*]\n");
144 }
145 /* time */
146 ✗ fprintf(plt, format, outputPath, prefix, 2+numFnsAndBlocks, 3+i, 3+i, 4);
147 fprintf(plt, "set nolog xy\n");
148 /* count */
149 ✗ if(i >= 0) {
150 fprintf(plt, "unset ytics\n");
151 ✗ if(nmin == nmax)
152 {
153 fprintf(plt, "set yrange [%g:%g]\n", ymin, ymax);
154 }
155 else
156 {
157 fprintf(plt, "set yrange [*:*]\n");
158 }
159 fprintf(plt, "set output \"%s%s_prof.%s%d_count.thumb.svg\"\n", outputPath, prefix, idPrefix, id);
160 ✗ fprintf(plt, formatCount, outputPath, prefix, 1+numFnsAndBlocks, 2+i, 4);
161 fprintf(plt, "set ytics\n");
162 }
163
164 /* SVG */
165 fprintf(plt, "set xtics\n");
166 fprintf(plt, "set ytics\n");
167 fprintf(plt, "set border\n");
168 fprintf(plt, "set terminal %s\n", plotFormat);
169 fprintf(plt, "set title \"%s\"\n", title);
170 fprintf(plt, "set xlabel \"Global step at time\"\n");
171 fprintf(plt, "set ylabel \"Execution time [s]\"\n");
172 fprintf(plt, "set output \"%s%s_prof.%s%d.%s\"\n", outputPath, prefix, idPrefix, id, plotFormat);
173 fprintf(plt, "set log y\n");
174 ✗ if(i>=0)
175 {
176 fprintf(plt, "set yrange [*:%g]\n", ygraphmax);
177 }
178 else
179 {
180 fprintf(plt, "set yrange [*:*]\n");
181 }
182 fprintf(plt, format, outputPath, prefix, 2+numFnsAndBlocks, 3+i, 3+i, 2);
183 /* count */
184 fprintf(plt, "set nolog xy\n");
185 ✗ if(i >= 0)
186 {
187 ✗ if(nmin == nmax)
188 {
189 fprintf(plt, "set yrange [%g:%g]\n", ymin, ymax);
190 }
191 else
192 {
193 fprintf(plt, "set yrange [*:*]\n");
194 }
195 fprintf(plt, "set xlabel \"Global step number\"\n");
196 fprintf(plt, "set ylabel \"Execution count\"\n");
197 fprintf(plt, "set output \"%s%s_prof.%s%d_count.%s\"\n", outputPath, prefix, idPrefix, id, plotFormat);
198 ✗ fprintf(plt, formatCount, outputPath, prefix, 1+numFnsAndBlocks, 2+i, 2);
199 }
200 }
201
202 ✗ static void printStrXML(FILE *fout, const char *str)
203 {
204 ✗ while(*str) {
205 ✗ switch (*str) {
206 ✗ case '<': fputs("&lt;",fout);break;
207 ✗ case '>': fputs("&gt;",fout);break;
208 ✗ case '\'': fputs("&apos;",fout);break;
209 ✗ case '"': fputs("&quot;",fout);break;
210 /* case '\\': fputs("\\\\",fout);break; */
211 ✗ default: fputc(*str,fout); break;
212 }
213 ✗ str++;
214 }
215 ✗ }
216
217 ✗ static void printInfoTag(FILE *fout, int level, const FILE_INFO info) {
218 indent(fout,level);
219 fprintf(fout, "<info filename=\"");
220 ✗ printStrXML(fout, info.filename);
221 ✗ fprintf(fout, "\" startline=\"%d\" startcol=\"%d\" endline=\"%d\" endcol=\"%d\" readonly=\"%s\" />\n", info.lineStart, info.colStart, info.lineEnd, info.colEnd, info.readonly ? "readonly" : "writable");
222 ✗ }
223
224 ✗ static void printVar(FILE *fout, int level, VAR_INFO* info) {
225
226 indent(fout,level);
227 ✗ fprintf(fout, "<variable id=\"var%d\" name=\"", info->id);
228 ✗ printStrXML(fout, info->name);
229 fprintf(fout, "\" comment=\"");
230 ✗ printStrXML(fout, info->comment);
231 fprintf(fout, "\">\n");
232 ✗ printInfoTag(fout, level+2, info->info);
233 indent(fout,level);
234 fprintf(fout, "</variable>\n");
235 ✗ }
236
237 ✗ static void printFunctions(FILE *fout, FILE *plt, const char *plotFormat, const char *outputPath, const char *modelFilePrefix, DATA *data) {
238 int i;
239 ✗ for(i=0; i<data->modelData->modelDataXml.nFunctions; i++) {
240 ✗ const struct FUNCTION_INFO func = modelInfoGetFunction(&data->modelData->modelDataXml, i);
241 ✗ printPlotCommand(plt, plotFormat, func.name, outputPath, modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks, i, func.id, "fun");
242 ✗ rt_clear(i + SIM_TIMER_FIRST_FUNCTION);
243 indent(fout,2);
244 fprintf(fout, "<function id=\"fun%d\">\n", func.id);
245 ✗ indent(fout,4);fprintf(fout, "<name>");printStrXML(fout, func.name);fprintf(fout,"</name>\n");
246 ✗ indent(fout,4);fprintf(fout, "<ncall>%d</ncall>\n", (int) rt_ncall_total(i + SIM_TIMER_FIRST_FUNCTION));
247 ✗ indent(fout,4);fprintf(fout, "<time>%.9f</time>\n",rt_total(i + SIM_TIMER_FIRST_FUNCTION));
248 ✗ indent(fout,4);fprintf(fout, "<maxTime>%.9f</maxTime>\n",rt_max_accumulated(i + SIM_TIMER_FIRST_FUNCTION));
249 ✗ printInfoTag(fout, 6, func.info);
250 indent(fout,2);
251 fprintf(fout, "</function>\n");
252 }
253 ✗ }
254
255 ✗ static void printProfileBlocks(FILE *fout, FILE *plt, const char *plotFormat, const char *outputPath, DATA *data) {
256 int i;
257 ✗ for(i = data->modelData->modelDataXml.nFunctions; i < data->modelData->modelDataXml.nFunctions + data->modelData->modelDataXml.nProfileBlocks; i++) {
258 ✗ const struct EQUATION_INFO eq = modelInfoGetEquationIndexByProfileBlock(&data->modelData->modelDataXml, i-data->modelData->modelDataXml.nFunctions);
259 ✗ printPlotCommand(plt, plotFormat, "equation", outputPath, data->modelData->modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks, i, eq.id, "eq");
260 ✗ rt_clear(i + SIM_TIMER_FIRST_FUNCTION);
261 indent(fout,2);fprintf(fout, "<profileblock>\n");
262 indent(fout,4);fprintf(fout, "<ref refid=\"eq%d\"/>\n", (int) eq.id);
263 ✗ indent(fout,4);fprintf(fout, "<ncall>%d</ncall>\n", (int) rt_ncall_total(i + SIM_TIMER_FIRST_FUNCTION));
264 ✗ indent(fout,4);fprintf(fout, "<time>%.9f</time>\n", rt_total(i + SIM_TIMER_FIRST_FUNCTION));
265 ✗ indent(fout,4);fprintf(fout, "<maxTime>%.9f</maxTime>\n",rt_max_accumulated(i + SIM_TIMER_FIRST_FUNCTION));
266 indent(fout,2);fprintf(fout, "</profileblock>\n");
267 }
268 ✗ }
269
270
271 ✗ static int getVarIdByName(DATA *data, const char* varName)
272 {
273 int i;
274 ✗ for(i=0;i<data->modelData->nVariablesReal;++i)
275 ✗ if (strcmp(varName, data->modelData->realVarsData[i].info.name) == 0)
276 ✗ return data->modelData->realVarsData[i].info.id;
277
278 ✗ for(i=0;i<data->modelData->nParametersReal;++i)
279 ✗ if (strcmp(varName, data->modelData->realParameterData[i].info.name) == 0)
280 ✗ return data->modelData->realParameterData[i].info.id;
281
282 ✗ for(i=0;i<data->modelData->nVariablesInteger;++i)
283 ✗ if (strcmp(varName, data->modelData->integerVarsData[i].info.name) == 0)
284 ✗ return data->modelData->integerVarsData[i].info.id;
285
286 ✗ for(i=0;i<data->modelData->nParametersInteger;++i)
287 ✗ if (strcmp(varName, data->modelData->integerParameterData[i].info.name) == 0)
288 ✗ return data->modelData->integerParameterData[i].info.id;
289
290 ✗ for(i=0;i<data->modelData->nVariablesBoolean;++i)
291 ✗ if (strcmp(varName, data->modelData->booleanVarsData[i].info.name) == 0)
292 ✗ return data->modelData->booleanVarsData[i].info.id;
293
294 ✗ for(i=0;i<data->modelData->nParametersBoolean;++i)
295 ✗ if (strcmp(varName, data->modelData->booleanParameterData[i].info.name) == 0)
296 ✗ return data->modelData->booleanParameterData[i].info.id;
297
298 ✗ for(i=0;i<data->modelData->nVariablesString;++i)
299 ✗ if (strcmp(varName, data->modelData->stringVarsData[i].info.name) == 0)
300 ✗ return data->modelData->stringVarsData[i].info.id;
301
302 ✗ for(i=0;i<data->modelData->nParametersString;++i)
303 ✗ if (strcmp(varName, data->modelData->stringParameterData[i].info.name) == 0)
304 ✗ return data->modelData->stringParameterData[i].info.id;
305
306 return 0;
307 }
308
309 ✗ static void printEquations(FILE *fout, int n, MODEL_DATA_XML *xml, DATA *data) {
310 int i,j;
311 ✗ for(i=0; i<n; i++) {
312 ✗ indent(fout,2);fprintf(fout, "<equation id=\"eq%d\">\n", modelInfoGetEquation(xml,i).id);
313 indent(fout,4);fprintf(fout, "<refs>\n");
314 ✗ for(j=0; j<modelInfoGetEquation(xml,i).numVar; j++) {
315 ✗ indent(fout,6);fprintf(fout, "<ref refid=\"var%d\" />\n", getVarIdByName(data, modelInfoGetEquation(xml,i).vars[j]));
316 }
317 indent(fout,4);fprintf(fout, "</refs>\n");
318 ✗ indent(fout,4);fprintf(fout, "<calcinfo time=\"%f\" count=\"%lu\"/>\n", rt_accumulated(SIM_TIMER_FIRST_FUNCTION + xml->nFunctions + xml->nProfileBlocks + modelInfoGetEquation(xml,i).id), (long) rt_ncall(SIM_TIMER_FIRST_FUNCTION + xml->nFunctions + xml->nProfileBlocks + modelInfoGetEquation(xml,i).id));
319 indent(fout,2);fprintf(fout, "</equation>\n");
320 }
321 ✗ }
322
323 ✗ static void printProfilingDataHeader(FILE *fout, DATA *data) {
324 char *filename;
325 int i;
326
327 ✗ filename = malloc(strlen(data->modelData->modelFilePrefix) + 15);
328 sprintf(filename, "%s_prof.data", data->modelData->modelFilePrefix);
329 ✗ indent(fout, 2); fprintf(fout, "<filename>");printStrXML(fout,filename);fprintf(fout,"</filename>\n");
330 ✗ indent(fout, 2); fprintf(fout, "<filesize>%ld</filesize>\n", (long) fileSize(filename));
331 ✗ free(filename);
332
333 indent(fout, 2); fprintf(fout, "<format>\n");
334 indent(fout, 4); fprintf(fout, "<uint32>step</uint32>\n");
335 indent(fout, 4); fprintf(fout, "<double>time</double>\n");
336 indent(fout, 4); fprintf(fout, "<double>cpu time</double>\n");
337 ✗ for(i = 0; i < data->modelData->modelDataXml.nFunctions; i++) {
338 ✗ const char *name = modelInfoGetFunction(&data->modelData->modelDataXml,i).name;
339 ✗ indent(fout, 4); fprintf(fout, "<uint32>");printStrXML(fout,name);fprintf(fout, " (calls)</uint32>\n");
340 }
341 ✗ for(i = 0; i < data->modelData->modelDataXml.nProfileBlocks; i++) {
342 ✗ int id = modelInfoGetEquationIndexByProfileBlock(&data->modelData->modelDataXml,i).id;
343 indent(fout, 4); fprintf(fout, "<uint32>Equation %d (calls)</uint32>\n", id);
344 }
345 ✗ for(i = 0; i < data->modelData->modelDataXml.nFunctions; i++) {
346 ✗ const char *name = modelInfoGetFunction(&data->modelData->modelDataXml,i).name;
347 ✗ indent(fout, 4); fprintf(fout, "<double>");printStrXML(fout,name);fprintf(fout, " (cpu time)</double>\n");
348 }
349 ✗ for(i = 0; i < data->modelData->modelDataXml.nProfileBlocks; i++) {
350 ✗ int id = modelInfoGetEquationIndexByProfileBlock(&data->modelData->modelDataXml,i).id;
351 indent(fout, 4); fprintf(fout, "<double>Equation %d (cpu time)</double>\n", id);
352 }
353 indent(fout, 2); fprintf(fout, "</format>\n");
354 ✗ }
355
356 ✗ int printModelInfo(DATA *data, threadData_t *threadData, const char *outputPath, const char *filename, const char *plotfile, const char *plotFormat, const char *method, const char *outputFormat, const char *outputFilename)
357 {
358 static char buf[256];
359 const char* fullFileName;
360 ✗ if (0 > GC_asprintf(&fullFileName, "%s%s", outputPath, filename)) {
361 ✗ throwStreamPrint(NULL, "modelinfo.c: Error: can not allocate memory.");
362 }
363 ✗ FILE *fout = omc_fopen(fullFileName, "w");
364 FILE *plotCommands;
365 time_t t;
366 int i;
367 #if defined(__MINGW32__) || defined(_MSC_VER) || defined(NO_PIPE)
368 const char* fullPlotFile;
369 ✗ if (0 > GC_asprintf(&fullPlotFile, "%s%s", outputPath, plotfile)) {
370 ✗ throwStreamPrint(NULL, "modelinfo.c: Error: can not allocate memory.");
371 }
372 ✗ plotCommands = omc_fopen(fullPlotFile, "w");
373 #else
374 plotCommands = popen("gnuplot", "w");
375 #endif
376 ✗ if (!plotCommands) {
377 ✗ warningStreamPrint(OMC_LOG_DIVISION, 0, "Plots of profiling data were disabled: %s\n", strerror(errno));
378 }
379
380 ✗ assertStreamPrint(threadData, 0 != fout, "Failed to open %s%s: %s\n", outputPath, filename, strerror(errno));
381
382 ✗ if(plotCommands) {
383 ✗ fputs("set terminal svg\n", plotCommands);
384 ✗ fputs("set nokey\n", plotCommands);
385 ✗ fputs("set format y \"%g\"\n", plotCommands);
386 /* The column containing the time spent to calculate each step */
387 ✗ printPlotCommand(plotCommands, plotFormat, "Execution time of global steps", outputPath, data->modelData->modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks, -1, 999, "");
388 }
389 /* The doctype is needed for id() lookup to work properly */
390 fprintf(fout, "<!DOCTYPE doc [\
391 <!ELEMENT simulation (modelinfo, variables, functions, equations)>\
392 <!ATTLIST variable id ID #REQUIRED>\
393 <!ELEMENT equation (refs)>\
394 <!ATTLIST equation id ID #REQUIRED>\
395 <!ELEMENT profileblocks (profileblock*)>\
396 <!ELEMENT profileblock (refs, ncall, time, maxTime)>\
397 <!ELEMENT refs (ref*)>\
398 <!ATTLIST ref refid IDREF #REQUIRED>\
399 ]>\n");
400 ✗ if(time(&t) < 0)
401 {
402 ✗ warningStreamPrint(OMC_LOG_DIVISION, 0, "time() failed: %s", strerror(errno));
403 ✗ fclose(fout);
404 #if defined(__MINGW32__) || defined(_MSC_VER) || defined(NO_PIPE)
405 ✗ fclose(plotCommands);
406 #else
407 pclose(plotCommands);
408 #endif
409 ✗ return 1;
410 }
411 ✗ if(!strftime(buf, 250, "%Y-%m-%d %H:%M:%S", localtime(&t)))
412 {
413 ✗ warningStreamPrint(OMC_LOG_DIVISION, 0, "strftime() failed");
414 ✗ fclose(fout);
415 ✗ return 1;
416 }
417 fprintf(fout, "<simulation>\n");
418 fprintf(fout, "<modelinfo>\n");
419 ✗ indent(fout, 2); fprintf(fout, "<name>");printStrXML(fout,data->modelData->modelName);fprintf(fout,"</name>\n");
420 ✗ indent(fout, 2); fprintf(fout, "<prefix>");printStrXML(fout,data->modelData->modelFilePrefix);fprintf(fout,"</prefix>\n");
421 ✗ indent(fout, 2); fprintf(fout, "<date>");printStrXML(fout,buf);fprintf(fout,"</date>\n");
422 ✗ indent(fout, 2); fprintf(fout, "<method>");printStrXML(fout,data->simulationInfo->solverMethod);fprintf(fout,"</method>\n");
423 ✗ indent(fout, 2); fprintf(fout, "<outputFormat>");printStrXML(fout,data->simulationInfo->outputFormat);fprintf(fout,"</outputFormat>\n");
424 ✗ indent(fout, 2); fprintf(fout, "<outputFilename>");printStrXML(fout,outputFilename);fprintf(fout,"</outputFilename>\n");
425 ✗ indent(fout, 2); fprintf(fout, "<outputFilesize>%ld</outputFilesize>\n", (long) fileSize(outputFilename));
426 ✗ indent(fout, 2); fprintf(fout, "<overheadTime>%f</overheadTime>\n", rt_accumulated(SIM_TIMER_OVERHEAD));
427 ✗ indent(fout, 2); fprintf(fout, "<preinitTime>%f</preinitTime>\n", rt_accumulated(SIM_TIMER_PREINIT));
428 ✗ indent(fout, 2); fprintf(fout, "<initTime>%f</initTime>\n", rt_accumulated(SIM_TIMER_INIT));
429 ✗ indent(fout, 2); fprintf(fout, "<eventTime>%f</eventTime>\n", rt_accumulated(SIM_TIMER_EVENT));
430 ✗ indent(fout, 2); fprintf(fout, "<outputTime>%f</outputTime>\n", rt_accumulated(SIM_TIMER_OUTPUT));
431 ✗ indent(fout, 2); fprintf(fout, "<jacobianTime>%f</jacobianTime>\n", rt_accumulated(SIM_TIMER_JACOBIAN));
432 ✗ indent(fout, 2); fprintf(fout, "<totalTime>%f</totalTime>\n", rt_accumulated(SIM_TIMER_TOTAL));
433 ✗ indent(fout, 2); fprintf(fout, "<totalStepsTime>%f</totalStepsTime>\n", rt_total(SIM_TIMER_STEP));
434 ✗ indent(fout, 2); fprintf(fout, "<numStep>%d</numStep>\n", (int) rt_ncall_total(SIM_TIMER_STEP));
435 ✗ indent(fout, 2); fprintf(fout, "<maxTime>%.9f</maxTime>\n", rt_max_accumulated(SIM_TIMER_STEP));
436 fprintf(fout, "</modelinfo>\n");
437
438 fprintf(fout, "<modelinfo_ext>\n");
439 ✗ indent(fout, 2); fprintf(fout, "<odeTime>%f</odeTime>\n", rt_accumulated(SIM_TIMER_FUNCTION_ODE));
440 ✗ indent(fout, 2); fprintf(fout, "<odeTimeTicks>%lu</odeTimeTicks>\n", (long) rt_ncall(SIM_TIMER_FUNCTION_ODE));
441 fprintf(fout, "</modelinfo_ext>\n");
442
443 fprintf(fout, "<profilingdataheader>\n");
444 ✗ printProfilingDataHeader(fout, data);
445 fprintf(fout, "</profilingdataheader>\n");
446
447 fprintf(fout, "<variables>\n");
448 ✗ for(i=0;i<data->modelData->nVariablesReal;++i){
449 ✗ printVar(fout, 2, &(data->modelData->realVarsData[i].info));
450 }
451 ✗ for(i=0;i<data->modelData->nParametersReal;++i){
452 ✗ printVar(fout, 2, &data->modelData->realParameterData[i].info);
453 }
454 ✗ for(i=0;i<data->modelData->nVariablesInteger;++i){
455 ✗ printVar(fout, 2, &data->modelData->integerVarsData[i].info);
456 }
457 ✗ for(i=0;i<data->modelData->nParametersInteger;++i){
458 ✗ printVar(fout, 2, &data->modelData->integerParameterData[i].info);
459 }
460 ✗ for(i=0;i<data->modelData->nVariablesBoolean;++i){
461 ✗ printVar(fout, 2, &data->modelData->booleanVarsData[i].info);
462 }
463 ✗ for(i=0;i<data->modelData->nParametersBoolean;++i){
464 ✗ printVar(fout, 2, &data->modelData->booleanParameterData[i].info);
465 }
466 ✗ for(i=0;i<data->modelData->nVariablesString;++i){
467 ✗ printVar(fout, 2, &data->modelData->stringVarsData[i].info);
468 }
469 ✗ for(i=0;i<data->modelData->nParametersString;++i){
470 ✗ printVar(fout, 2, &data->modelData->stringParameterData[i].info);
471 }
472 fprintf(fout, "</variables>\n");
473
474 fprintf(fout, "<functions>\n");
475 ✗ printFunctions(fout, plotCommands, plotFormat, outputPath, data->modelData->modelFilePrefix, data);
476 fprintf(fout, "</functions>\n");
477
478 fprintf(fout, "<equations>\n");
479 ✗ printEquations(fout, data->modelData->modelDataXml.nEquations, &data->modelData->modelDataXml, data);
480 fprintf(fout, "</equations>\n");
481
482 fprintf(fout, "<profileblocks>\n");
483 ✗ printProfileBlocks(fout, plotCommands, plotFormat, outputPath, data);
484 fprintf(fout, "</profileblocks>\n");
485
486 fprintf(fout, "</simulation>\n");
487
488 ✗ fclose(fout);
489 ✗ if(plotCommands) {
490 ✗ const char *omhome = data->simulationInfo->OPENMODELICAHOME;
491 char *buf = NULL;
492 int genHtmlRes;
493 ✗ buf = (char*)malloc(230 + 4 + 2*strlen(plotfile) + 2*strlen(outputPath) + 2*(omhome ? strlen(omhome) : 0));
494 ✗ assert(buf);
495 #if defined(__MINGW32__) || defined(_MSC_VER) || defined(NO_PIPE)
496 ✗ if(omhome) {
497 #if defined(__MINGW32__) || defined(_MSC_VER)
498 sprintf(buf, "\"\"%s/lib/omc/libexec/gnuplot/binary/gnuplot.exe\" %s%s\"", omhome, outputPath, plotfile);
499 #else
500 sprintf(buf, "gnuplot %s", plotfile);
501 #endif
502 ✗ fclose(plotCommands);
503 ✗ if (measure_time_flag & 4 && 0 != system(buf)) {
504 ✗ warningStreamPrint(OMC_LOG_DIVISION, 0, "Plot command failed: %s\n", buf);
505 }
506 }
507 #else
508 if(0 != pclose(plotCommands)) {
509 warningStreamPrint(OMC_LOG_DIVISION, 0, "Warning: Plot command failed\n");
510 }
511 #endif
512 ✗ if(omhome)
513 {
514 #if defined(__MINGW32__) || defined(_MSC_VER)
515 char *xsltproc;
516 sprintf(buf, "%s/lib/omc/libexec/xsltproc/xsltproc.exe", omhome);
517 xsltproc = omc_strdup(buf);
518 #else
519 const char *xsltproc = "xsltproc";
520 #endif
521
522 #if defined(__MINGW32__) || defined(_MSC_VER)
523 sprintf(buf, "\"\"%s\" -o %s%s_prof.html \"%s/share/omc/scripts/default_profiling.xsl\" %s%s_prof.xml\"", xsltproc, outputPath, data->modelData->modelFilePrefix, omhome, outputPath, data->modelData->modelFilePrefix);
524 #else
525 ✗ sprintf(buf, "%s -o %s%s_prof.html %s/share/omc/scripts/default_profiling.xsl %s%s_prof.xml", xsltproc, outputPath, data->modelData->modelFilePrefix, omhome, outputPath, data->modelData->modelFilePrefix);
526 #endif
527
528 #if defined(__MINGW32__) || defined(_MSC_VER)
529 free(xsltproc);
530 #endif
531 ✗ genHtmlRes = measure_time_flag & 4 && system(buf);
532 }
533 else
534 {
535 strcpy(buf, "OPENMODELICAHOME missing");
536 genHtmlRes = 1;
537 }
538 if(genHtmlRes)
539 {
540 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "Failed to generate html version of profiling results: %s\n", buf);
541 }
542 ✗ if (measure_time_flag & 4) {
543 ✗ infoStreamPrint(OMC_LOG_STDOUT, 0, "Time measurements are stored in %s%s_prof.html (human-readable) and %s%s_prof.xml (for XSL transforms or more details)", outputPath, data->modelData->modelFilePrefix, outputPath, data->modelData->modelFilePrefix);
544 } else {
545 ✗ infoStreamPrint(OMC_LOG_STDOUT, 0, "Time measurements are stored in %s%s_prof.json", outputPath, data->modelData->modelFilePrefix);
546 }
547 ✗ free(buf);
548 }
549 return 0;
550 }
551
552 #define ERROR_WRITE() throwStreamPrint(NULL, "Failed to write to opened file")
553
554 ✗ void escapeJSON(FILE *file, const char *data)
555 {
556 ✗ while (*data) {
557 ✗ switch (*data) {
558 ✗ case '\"': if (fputs("\\\"",file)<0) ERROR_WRITE();break;
559 ✗ case '\\': if (fputs("\\\\",file)<0) ERROR_WRITE();break;
560 ✗ case '\n': if (fputs("\\n",file)<0) ERROR_WRITE();break;
561 ✗ case '\b': if (fputs("\\b",file)<0) ERROR_WRITE();break;
562 ✗ case '\f': if (fputs("\\f",file)<0) ERROR_WRITE();break;
563 ✗ case '\r': if (fputs("\\r",file)<0) ERROR_WRITE();break;
564 ✗ case '\t': if (fputs("\\t",file)<0) ERROR_WRITE();break;
565 ✗ default:
566 ✗ if (*data < ' ') { /* Escape other control characters */
567 ✗ if (fprintf(file, "\\u%04x",*data)<0) ERROR_WRITE();
568 } else {
569 ✗ if (putc(*data,file)<0) ERROR_WRITE();
570 }
571 }
572 ✗ data++;
573 }
574 ✗ }
575
576 ✗ static void printJSONFunctions(FILE *fout, DATA *data) {
577 int i;
578 ✗ for(i = 0; i < data->modelData->modelDataXml.nFunctions; i++) {
579 ✗ const struct FUNCTION_INFO func = modelInfoGetFunction(&data->modelData->modelDataXml, i);
580 ✗ rt_clear(i + SIM_TIMER_FIRST_FUNCTION);
581 ✗ fputs(i == 0 ? "\n" : ",\n", fout);
582 fprintf(fout, "{\"name\":\"");
583 ✗ escapeJSON(fout, func.name);
584 ✗ fprintf(fout, "\",\"ncall\":%d,\"time\":%.9f,\"maxTime\":%.9f}",
585 ✗ (int) rt_ncall_total(i + SIM_TIMER_FIRST_FUNCTION),
586 rt_total(i + SIM_TIMER_FIRST_FUNCTION),
587 rt_max_accumulated(i + SIM_TIMER_FIRST_FUNCTION));
588 }
589 ✗ }
590
591 ✗ static void printJSONProfileBlocks(FILE *fout, DATA *data) {
592 int i;
593 ✗ for(i = data->modelData->modelDataXml.nFunctions; i < data->modelData->modelDataXml.nFunctions + data->modelData->modelDataXml.nProfileBlocks; i++) {
594 ✗ const struct EQUATION_INFO eq = modelInfoGetEquationIndexByProfileBlock(&data->modelData->modelDataXml, i-data->modelData->modelDataXml.nFunctions);
595 ✗ rt_clear(i + SIM_TIMER_FIRST_FUNCTION);
596 ✗ fputs(i == data->modelData->modelDataXml.nFunctions ? "\n" : ",\n", fout);
597 ✗ fprintf(fout, "{\"id\":%d,\"ncall\":%d,\"time\":%.9f,\"maxTime\":%.9f}",
598 ✗ (int) eq.id,
599 ✗ (int) rt_ncall_total(i + SIM_TIMER_FIRST_FUNCTION),
600 rt_total(i + SIM_TIMER_FIRST_FUNCTION),
601 rt_max_accumulated(i + SIM_TIMER_FIRST_FUNCTION));
602 }
603 ✗ }
604
605 ✗ int printModelInfoJSON(DATA *data, threadData_t *threadData, const char *outputPath, const char *filename, const char *outputFilename)
606 {
607 char buf[256];
608 const char* fullFileName;
609 ✗ if (0 > GC_asprintf(&fullFileName, "%s%s", outputPath, filename)) {
610 ✗ throwStreamPrint(NULL, "modelinfo.c: Error: can not allocate memory.");
611 }
612 ✗ FILE *fout = omc_fopen(fullFileName, "wb");
613 time_t t;
614 long i;
615 double totalTimeEqs = 0;
616 ✗ if (!fout) {
617 ✗ throwStreamPrint(NULL, "Failed to open file %s%s for writing", outputPath, filename);
618 }
619 ✗ convertProfileData(outputPath, data->modelData->modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks);
620 ✗ if(time(&t) < 0)
621 {
622 ✗ fclose(fout);
623 ✗ throwStreamPrint(0, "time() failed: %s", strerror(errno));
624 }
625 ✗ if(!strftime(buf, 250, "%Y-%m-%d %H:%M:%S", localtime(&t)))
626 {
627 ✗ fclose(fout);
628 ✗ throwStreamPrint(0, "strftime() failed");
629 }
630 ✗ for (i=data->modelData->modelDataXml.nFunctions; i<data->modelData->modelDataXml.nFunctions + data->modelData->modelDataXml.nProfileBlocks; i++) {
631 ✗ if (modelInfoGetEquation(&data->modelData->modelDataXml,i).parent == 0) {
632 /* The equation has no parent. The sum of all such equations is
633 * the total time of the profiled blocks including the children. */
634 ✗ totalTimeEqs += rt_total(i + SIM_TIMER_FIRST_FUNCTION);
635 }
636 }
637 fprintf(fout, "{\n\"name\":\"");
638 ✗ escapeJSON(fout, data->modelData->modelName);
639 fprintf(fout, "\",\n\"prefix\":\"");
640 ✗ escapeJSON(fout, data->modelData->modelFilePrefix);
641 fprintf(fout, "\",\n\"date\":\"");
642 ✗ escapeJSON(fout, buf);
643 fprintf(fout, "\",\n\"method\":\"");
644 ✗ escapeJSON(fout, data->simulationInfo->solverMethod);
645 fprintf(fout, "\",\n\"outputFormat\":\"");
646 ✗ escapeJSON(fout, data->simulationInfo->outputFormat);
647 fprintf(fout, "\",\n\"outputFilename\":\"");
648 ✗ escapeJSON(fout, outputFilename);
649 ✗ fprintf(fout, "\",\n\"outputFilesize\":%ld",(long) fileSize(outputFilename));
650 ✗ fprintf(fout, ",\n\"overheadTime\":%g",rt_accumulated(SIM_TIMER_OVERHEAD));
651 ✗ fprintf(fout, ",\n\"preinitTime\":%g",rt_accumulated(SIM_TIMER_PREINIT));
652 ✗ fprintf(fout, ",\n\"initTime\":%g",rt_accumulated(SIM_TIMER_INIT));
653 ✗ fprintf(fout, ",\n\"eventTime\":%g",rt_accumulated(SIM_TIMER_EVENT));
654 ✗ fprintf(fout, ",\n\"outputTime\":%g",rt_accumulated(SIM_TIMER_OUTPUT));
655 ✗ fprintf(fout, ",\n\"jacobianTime\":%g",rt_accumulated(SIM_TIMER_JACOBIAN));
656 ✗ fprintf(fout, ",\n\"totalTime\":%g",rt_accumulated(SIM_TIMER_TOTAL));
657 ✗ fprintf(fout, ",\n\"totalStepsTime\":%g",rt_accumulated(SIM_TIMER_STEP));
658 fprintf(fout, ",\n\"totalTimeProfileBlocks\":%g",totalTimeEqs); /* The overhead the profiling is huge if small equations are profiled */
659 ✗ fprintf(fout, ",\n\"numStep\":%d", (int) rt_ncall_total(SIM_TIMER_STEP));
660 ✗ fprintf(fout, ",\n\"maxTime\":%.9g", rt_max_accumulated(SIM_TIMER_STEP));
661 fprintf(fout, ",\n\"functions\":[");
662 ✗ printJSONFunctions(fout,data);
663 fprintf(fout, "\n],\n\"profileBlocks\":[");
664 ✗ printJSONProfileBlocks(fout,data);
665 fprintf(fout, "\n]\n");
666 fprintf(fout, "}");
667 ✗ return 0;
668 }
669