From 81eb0851bdf590ac828de57ddd98e1a1fbae1088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Sj=C3=B6lund?= Date: Fri, 25 Sep 2026 18:03:41 +0200 Subject: [PATCH] Add a wasm-web job It simulates every model with --simCodeTarget=wasm-jit the way the web omc does: the driver and the solvers in wasm, the in-wasm libm, and external "C" only from prebuilt wasm libraries. Filling wasm-web beside wasm-jit shows what the browser path costs and which models it loses. The job has its own omc build, configured with -DRUST_OMC_WASM_INWASM_DRIVER=ON, and selects web mode through the OMC_WASM_* variables in wasmWebEnv(). It needs an OpenModelica with that option; on one without it the job fails. Assisted-by: Claude Opus 5.5 --- .CI/Jenkinsfile | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/.CI/Jenkinsfile b/.CI/Jenkinsfile index 1e28f8d..7acda0e 100644 --- a/.CI/Jenkinsfile +++ b/.CI/Jenkinsfile @@ -36,6 +36,7 @@ pipeline { booleanParam(name: 'ida', defaultValue: false, description: 'master branch, simulated with -s ida, filling ida (ryzen-5950x-1). Ticking it together with master, cvode or gbode runs one job that builds every model once and simulates it with each of them. This is an experimental job that does not run on a fixed schedule.') booleanParam(name: 'generateSymbolicJacobian', defaultValue: false, description: 'master branch, with --generateSymbolicJacobian (ryzen-5950x-1). This is an experimental job that does not run on a fixed schedule.') booleanParam(name: 'wasm_jit', defaultValue: false, description: 'master branch, with --simCodeTarget=wasm-jit (ryzen-9950x). Every model is translated and simulated the way simulate() does, filling wasm-jit. This is an experimental job that does not run on a fixed schedule.') + booleanParam(name: 'wasm_web', defaultValue: false, description: 'master branch, with --simCodeTarget=wasm-jit (ryzen-9950x), simulated the way the web omc does: the driver and the linear and nonlinear solvers in wasm, the in-wasm libm, and external "C" only from prebuilt wasm libraries. Fills wasm-web. This is an experimental job that does not run on a fixed schedule.') booleanParam(name: 'wasm_fmu', defaultValue: false, description: 'master branch, with --simCodeTarget=wasm-jit (ryzen-9950x). Every model is exported once as an unzipped wasm FMU and simulated through both of its FMI 3.0 interfaces, filling wasm-jit-me (Model Exchange) and wasm-jit-cs (Co-Simulation). This is an experimental job that does not run on a fixed schedule.') booleanParam(name: 'c_plus_rust', defaultValue: false, description: 'master branch, with --simCodeTarget=C+Rust, filling c-plus-rust (ryzen-5950x-1). The C code generator emits what it always did; the executable links libSimulationRuntimeRust instead of libSimulationRuntimeC, so the difference against master is the simulation runtime alone. This is an experimental job that does not run on a fixed schedule.') booleanParam(name: 'heavy_tests', defaultValue: false, description: 'master branch, runs one test at a time. That is, no parallel launching of tests. omc will use multiple threads for each test (-n=1 is not set unlike the other regression tests.), (ryzen-5950x-1). This is an experimental job that does not run on a fixed schedule.') @@ -365,6 +366,27 @@ pipeline { wasmCmakeFlags()) } } + stage('wasm-web') { + agent { + node { + label 'ryzen-9950x' + customWorkspace 'ws/OpenModelicaLibraryTestingWork' + } + } + options { skipDefaultCheckout() } + when { + beforeAgent true + expression { params.wasm_web } + } + steps { + // Its own build (~/saved_omc/wasm-web): the runtime links the web's in-wasm + // driver and solvers, which the environment below selects. + withEnv(wasmWebEnv()) { + runRegressiontest('master', 'wasm-web', 'setCommandLineOptions("--simCodeTarget=wasm-jit")', '', false, '', '--nobuildmodel', false, false, 0, 'configs/conf.json', + wasmCmakeFlags() + ' -DRUST_OMC_WASM_INWASM_DRIVER=ON') + } + } + } stage('C+Rust') { agent { node { @@ -480,7 +502,7 @@ pipeline { } when { beforeAgent true - expression { params.v1_25 || params.v1_26 || params.v1_27 || params.master || params.conversion_script || params.report_ryzen_5950x_1 || params.report_ryzen_5950x_2 || params.newInst_newBackend || params.generateSymbolicJacobian || params.heavy_tests || params.fmi_v1_25 || params.fmi_v1_26 || params.fmi_v1_27 || params.fmi_master || params.fmpy_fmi_v1_25 || params.fmpy_fmi_v1_26 || params.fmpy_fmi_v1_27 || params.fmpy_fmi_master || params.newInst_daeMode || params.newBackend_daeMode || params.oldInst || params.cpp || params.cvode || params.gbode || params.ida || params.wasm_jit || params.wasm_fmu || params.c_plus_rust} + expression { params.v1_25 || params.v1_26 || params.v1_27 || params.master || params.conversion_script || params.report_ryzen_5950x_1 || params.report_ryzen_5950x_2 || params.newInst_newBackend || params.generateSymbolicJacobian || params.heavy_tests || params.fmi_v1_25 || params.fmi_v1_26 || params.fmi_v1_27 || params.fmi_master || params.fmpy_fmi_v1_25 || params.fmpy_fmi_v1_26 || params.fmpy_fmi_v1_27 || params.fmpy_fmi_master || params.newInst_daeMode || params.newBackend_daeMode || params.oldInst || params.cpp || params.cvode || params.gbode || params.ida || params.wasm_jit || params.wasm_fmu || params.wasm_web || params.c_plus_rust} } environment { GITBRANCHES = 'maintenance/v1.20 maintenance/v1.21 maintenance/v1.22 maintenance/v1.23 maintenance/v1.24 maintenance/v1.25 maintenance/v1.26 maintenance/v1.27 master newInst-newBackend' @@ -489,7 +511,7 @@ pipeline { GITBRANCHES_DAE = 'newInst-daeMode' GITBRANCHES_NEWBACKEND_DAE = 'newBackend-daeMode' GITBRANCHES_CPP = 'v1.19-cpp v1.20-cpp v1.21-cpp v1.22-cpp v1.23-cpp v1.24-cpp v1.25-cpp cpp v1.26-cpp v1.27-cpp' - GITBRANCHES_WASM_JIT = 'wasm-jit-me wasm-jit-cs wasm-jit' + GITBRANCHES_WASM_JIT = 'wasm-jit-me wasm-jit-cs wasm-jit wasm-web' GITBRANCHES_C_PLUS_RUST = 'c-plus-rust' GITBRANCHES_SPECIAL = 'master newInst-newBackend' // The C+Rust job ran a few times before it was added to this stage, so @@ -585,9 +607,10 @@ pipeline { sh "./report.py --branches='ida master' configs/conf.json" sh "mv overview.html overview-ida.html" - // The three ways a wasm-jit model is simulated, against master: the plain - // simulation path, and the two FMI 3.0 interfaces of one exported wasm FMU, - // which share an export and differ only in simulation and verification. + // The ways a wasm-jit model is simulated, against master: the plain + // simulation path, the two FMI 3.0 interfaces of one exported wasm FMU, + // which share an export and differ only in simulation and verification, + // and the web omc's in-wasm path. sh "./report.py --branches='master ${env.GITBRANCHES_C_PLUS_RUST} ${env.GITBRANCHES_WASM_JIT}' configs/conf.json" sh "mv overview.html overview-wasm-jit.html" @@ -877,6 +900,14 @@ def wasmCmakeFlags() { return '-DOM_OMC_ENABLE_RUST=ON -DRUST_OMC_CI=ON -DRUST_OMC_THREADS=4 -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache' } +/* What makes the wasm-web job's omc simulate the way the web omc does. */ +def wasmWebEnv() { + return ['OMC_WASM_INWASM_DRIVER=1', + 'OMC_WASM_HOST_LIN_SOLVE=0', + 'OMC_WASM_HOST_LIBM=0', + 'OMC_WASM_NATIVE_EXTERNALS=0'] +} + def runRegressiontest(branch, name, extraFlags, omsHash, omcompiler, extrasimflags, testFlags, boolean removePackageOrder, boolean conversionScript, int jobs=0, libs_config_file = 'configs/conf.json', cmakeFlags = '', dockerfile = '.CI/testing', fmiSimulators = null, solvers = null) { sh ''' find /tmp -name "*openmodelica.hudson*" -exec rm {} ";" || true