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("<",fout);break; | |
| 207 | ✗ | case '>': fputs(">",fout);break; | |
| 208 | ✗ | case '\'': fputs("'",fout);break; | |
| 209 | ✗ | case '"': fputs(""",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 |