This report contains data analysis for the paper “Incremental View Model Synchronization Using Partial Models”.

The source code of the ViewModel tool is available under the terms of the Eclipse Public License, version 1.0 at https://github.com/FTSRG/viewmodel.

For a simplified benchmarking campaign that can be executed on a desktop computer, see viewmodel-data-analysis-results-short.html.

Evaluation

Research questions

Our view transformation approach is fully implemented as an open source project. We carried out an experimental evaluation to address three research questions:

RQ1. What is the complexity of different execution phases in our view transformation engine?

RQ2. What is the performance overhead for the initial run of our view transformation engine compared to reactive imperative transformations with explicit traceability?

RQ3. What is the performance overhead for change-driven behavior of our view transformation engine compared to reactive imperative transformations with explicit traceability?

Case studies

We selected two substantially different view transformation challenges for our investigation.

  1. VirtualSwitch is a filtering transformation taken from the VAO’14 paper Query-driven incremental synchronization of view models (see the publication page for details). The implementation of this case study is available in the ViewModel repository.

  2. Dependability is an extended version of the case study used in this paper which aims to compose two separate transformations in a way that the target Petri net model is significantly larger than any of the two source models. The implementation of this case study is available in the ViewModel repository.

We believe that these transformations are representative for key practical applications of view transformations: the VirtualSwitch scenario is typical for in traditional view models with information loss while the transformation challenges in the Dependability case are common for the formal analysis of extra-functional properties of systems.

Compared approaches

First, we instrumented our ViewModel transformation approach to enable the clear separation of different transformation phases to address RQ1. Then we compare our approach with two different view transformation styles available in VIATRA. These solutions use an explicit traceability model (vs. implicit traceability in our approach) and imperative actions in transformation rules using Java/Xtend (vs. declarative query-based templates). However, differences in query performance can be mitigated to a large extent. (1.a) The source-reactive solution uses exactly the same source queries as our view transformation approach, but rule priorities had to be set carefully. (1.b) The trace-reactive solution uses queries with both source and traceability elements as part of its precondition. Since both the level of compositionality and the properties of the view transformation engine are different in these approaches compared to our view transformation approach, our evaluation may reveal the performance trade-offs of the increased expressiveness of our approach.

Our repository contains an implementation of the transformations in batch ATL and a partial implementation in eMoflon, but the different performance optimizations in those tools would disallow to separate query performance from transformation performance.

Experiment setup

To investigate the initial transformation runs RQ2, our measurement setup contains 5 source models of increasing size. For the VirtualSwitch case, the source models were ranging from 25K to 425K elements, while the target models were ranging from 500 to 9K elements. For the Dependability case, the source models ranged 1K to 25K while the target models ranged from 3K to 72K. In each case, we measured the initial time for populating the caches of queries and the execution time of the first transformation, while the load time of source models was excluded. To address RQ1, we measure how much time the different phases of our view transformation approach takes during this initial run.

To investigate the change-driven behavior (RQ3), we first created 10 different elementary changes (modifications of one element) and 5 change mixes containing 100 elementary changes each (with fix ratio between different types of change within each mix).

Change mix (A) presents a balanced mix of changes, while types of changes in mixes (B) and (C) were selected from those elementary changes that caused longer synchronization times in the Dependability and VirtualSwitch cases, respectively. Mix (D) were selected from changes that caused longer synchronization times in at least one of cases as a compromise between B and C, where changes in (E) caused longer synchronization times in neither.

Elementary change Mix (A) Mix (B) Mix (C) Mix (D) Mix (E)
Create switch 10 25 0 12 0
Create segment 10 0 0 0 50
Connect track elements 10 0 0 0 50
Disconnect track elements 10 0 33 16 0
Create route 5 25 0 12 0
Remove route 5 5 0 5 0
Add switch to route 10 20 0 10 0
Remove switch from route 10 25 0 12 0
Set switch failed 15 0 34 17 0
Set switch operational 15 0 33 16 0

Each experiment was executed 30 times after 10 warmup runs on a cloud-based virtual environment (with 4 CPU, 16 GB memory and 8 GB disk size, m5.xlarge) on Amazon AWS. Heap space of the Java virtual machine was limited to 15 GB.

Running the benchmark

The archives hu.bme.mit.inf.viewmodel.benchmarks.product-linux.gtk.x86_64, hu.bme.mit.inf.viewmodel.benchmarks.product-macosx.cocoa.x86_64 or hu.bme.mit.inf.viewmodel.benchmarks.product-win32.win32.x86_64 contain the Eclipse application, example models, and .json configuration files for various transformation cases and model modification mixes. Execute the benchmark with

./eclipse -benchmarks <CONFIGURATION FILE>.json -vmargs -Xmx15g

The configuration files d_batch.json, d_1.json, d_2.json, …, d_15.json, as well as vs_batch.json, vs_1.json, vs_2.json, …, vs_15.json can be ran on separate virtual machines. To facilitate this, outputs are written to the folder /mnt/results, where a shared filesystem can be mounted to collect results.

After the benchmarks above are finished, the produces benchmarks.log files should be concatenated into a single full_log.csv file (mind the csv headers! they should be removed from all but the first log file). The full_log.csv file should be placed into the same directory as this R Markdown file for furter analysis.

Loading the data

The rest of the analysis proceeds as a literate R script. First we load the tidyverse packages for data wrangling and plotting.

require(tidyverse)

The file full_log.csv is the concatenation of the log files produced by the benchmark configurations d_batch.json, d_1.json, d_2.json, …, d_15.json, as well as vs_batch.json, vs_1.json, vs_2.json, …, vs_15.json.

log_path <- './full_log.csv'
full_log <- read_csv(log_path, col_types = cols(
  model = col_character(),
  transformationCase = col_character(),
  experiment = col_character(),
  modificationMix = col_character(),
  rerun = col_integer(),
  variable = col_character(),
  value = col_double()
))

We only measured using Train Benchmark models, so we can replace the model name with the scale factor in the logs, while still preserving all information.

trainbenchmark_log <- full_log %>%
  mutate(modelSize = as.integer(gsub('railway-batch-', '', model))) %>%
  select(-model) %>%
  separate(variable, c('checkpoint', 'category', 'variable'))

Basic statistics

We define some helper function for converting string identifiers to factor variables later.

TransformationCaseFactor <- function (v) {
  factor(as.factor(v),
         levels = c('dependability', 'virtualSwitch'),
         labels = c('Dependability', 'VirtualSwitch'))
}

ModificationMixFactor <- function (v) {
  factor(as.factor(v),
         levels = c('modelQuery', 'execute', 'usual', 'petriNetSlow', 'virtualSwitchSlow',
                    'bothSlow', 'bothFast', 'createSwitch', 'createSegment',
                    'connectTrackElements', 'disconnectTrackElements', 'createRoute', 'removeRoute',
                    'addSwitchToRoute', 'removeSwitchFromRoute',
                    'setSwitchFailed', 'setSwitchOperational'),
         labels = c('Initial query', 'Initial transformation', '(A) Usual mix', '(B) Depend. stress mix',
                    '(C) VirtSw. stress mix', '(D) mix', '(E) mix', 'Create switch', 'Create segment',
                    'Connect tract elements', 'Disconnect track elements', 'Create route', 'Remove route',
                    'Add switch to route', 'Remove switch from route',
                    'Set switch failed', 'Set switch operational'))
}

ExperimentFactor <- function (v) {
  factor(as.factor(v),
         levels = c('viewModel-physical', 'viatra-priorities', 'viatra'),
         labels = c('Our approach', 'Source-reactive VIATRA', 'Trace-reactive VIATRA'))
}

Source model statistics

We create a data frame containing size of the source models (object, reference and attribute counts). Each run prints the model sizes. However, we only use the output from the first batch run, because all source models with the same scale factor are identical.

source_model_statistics <- trainbenchmark_log %>%
  filter(experiment == 'viewModel-batch-physical' &
           modificationMix == 'none' &
           rerun == 0 &
           checkpoint == 'batch' &
           category == 'source') %>%
  group_by(modelSize, variable) %>%
  summarize(value = first(value)) %>%
  mutate(variable = paste0('source_', variable)) %>%
  spread(variable, value)

stat_df <- data.frame(source_model_statistics$modelSize, source_model_statistics$source_count, source_model_statistics$source_referenceCount, source_model_statistics$source_attributeCount)

colnames(stat_df) <- c("Scale factor", "Source objects", "Source references", "Source attributes")
knitr::kable(stat_df, format='markdown') %>% cat(sep = '\n')
Scale factor Source objects Source references Source attributes
1 1014 3955 1865
2 2039 7958 3752
4 4565 17842 8403
8 12213 47810 22495
16 25259 98926 46524
32 49799 194960 91735
64 101697 398278 187327
128 207953 814472 383068
256 425303 1665988 783457

Target model statistics

Batch transformations

We perform the same analysis for the target models of the batch transformations.

target_model_statistics <- trainbenchmark_log %>%
  filter(experiment == 'viewModel-batch-physical' &
           modificationMix == 'none' &
           rerun == 0 &
           checkpoint == 'batch' &
           category == 'target') %>%
  group_by(modelSize, transformationCase, variable) %>%
  summarize(value = first(value)) %>%
  mutate(variable = paste0('target_', variable)) %>%
  spread(variable, value)

tstat_cases <- TransformationCaseFactor(target_model_statistics$transformationCase)
tstat_df <- data.frame(target_model_statistics$modelSize, tstat_cases, target_model_statistics$target_count, target_model_statistics$target_referenceCount, target_model_statistics$target_attributeCount)

colnames(tstat_df) <- c("Scale factor", "Case study", "Target objects", "Target references", "Target attributes")
knitr::kable(tstat_df, format='markdown') %>% cat(sep = '\n')
Scale factor Case study Target objects Target references Target attributes
1 Dependability 2941 7840 2354
2 Dependability 5911 15760 4732
4 Dependability 13171 35120 10544
8 Dependability 35101 93600 28096
16 Dependability 72436 193160 57980
16 VirtualSwitch 495 325 495
32 VirtualSwitch 1040 708 1040
64 VirtualSwitch 2060 1370 2060
128 VirtualSwitch 4249 2841 4249
256 VirtualSwitch 8761 5869 8761

For sanity, we check that all transformations resulted in the same number of target model elements.

bad_batch_transformations <- trainbenchmark_log %>%
  filter(modificationMix == 'none' &
           checkpoint == 'batch' &
           category == 'target') %>%
  select(-c(modificationMix, checkpoint, category)) %>%
  mutate(variable = paste0('actual_', variable)) %>%
  spread(variable, value) %>%
  inner_join(target_model_statistics, by=c('transformationCase', 'modelSize')) %>%
  filter(actual_rootCount != target_rootCount |
           actual_count != target_count |
           actual_referenceCount != target_referenceCount |
           actual_attributeCount != target_attributeCount)

if (nrow(bad_batch_transformations) != 0) {
  print(bad_batch_transformations)
  stop("Unexpected batch transformation results")
} else {
  message("All correct")
}
## All correct

We may see that every batch transformation resulted in the expected number of target elements.

Now we count the variables and constraints in the partial models.

partial_size <- trainbenchmark_log %>%
  filter(modificationMix == 'none' &
           checkpoint == 'batch' & category == 'trace' &
           variable %in% c('variableCount', 'constraintCount') &
           rerun == 0) %>%
  select(c(transformationCase, variable, value, modelSize)) %>%
  spread(variable, value)

partial_cases <- TransformationCaseFactor(partial_size$transformationCase)
partial_df = data.frame(partial_size$modelSize, partial_cases, partial_size$variableCount, partial_size$constraintCount)

colnames(partial_df) <- c("Scale factor", "Case study", "Partial model variables", "Partial model constraints")
knitr::kable(partial_df, format='markdown') %>% cat(sep = '\n')
Scale factor Case study Partial model variables Partial model constraints
1 Dependability 9023 16277
2 Dependability 18137 32719
4 Dependability 40413 72907
8 Dependability 107689 194285
16 Dependability 222231 400936
16 VirtualSwitch 2135 3280
32 VirtualSwitch 4536 6992
64 VirtualSwitch 8920 13720
128 VirtualSwitch 18429 28360
256 VirtualSwitch 38021 58520

Change-driven transformations

Different modification mixed produce different output models, so we also collect statistics for the target model after each modification mix separately.

incremental_target_model_statistics <- trainbenchmark_log %>%
  filter(experiment == 'viewModel-incremental-physical' &
           modificationMix != 'none' &
           rerun == 0 &
           checkpoint == 'after' &
           category == 'target') %>%
  group_by(modelSize, transformationCase, modificationMix, variable) %>%
  summarize(value = first(value)) %>%
  mutate(variable = paste0('target_', variable)) %>%
  spread(variable, value) %>%
  ungroup()

incremental_tstat_df <- data.frame(
  incremental_target_model_statistics$modelSize,
  TransformationCaseFactor(incremental_target_model_statistics$transformationCase),
  ModificationMixFactor(incremental_target_model_statistics$modificationMix),
  incremental_target_model_statistics$target_count,
  incremental_target_model_statistics$target_referenceCount,
  incremental_target_model_statistics$target_attributeCount) %>%
  arrange_at(c(2, 1, 3))

colnames(incremental_tstat_df) <- c("Scale factor", "Case study", "Modification mix", "Target objects", "Target references", "Target attributes")
knitr::kable(incremental_tstat_df, format='markdown') %>% cat(sep = '\n')
Scale factor Case study Modification mix Target objects Target references Target attributes
1 Dependability (A) Usual mix 2125 5480 1646
1 Dependability (B) Depend. stress mix 2919 7660 2308
1 Dependability (C) VirtSw. stress mix 2941 7840 2354
1 Dependability (D) mix 2148 5524 1662
1 Dependability (E) mix 2941 7840 2354
1 Dependability Create switch 2949 7860 2360
1 Dependability Create segment 2941 7840 2354
1 Dependability Connect tract elements 2941 7840 2354
1 Dependability Disconnect track elements 2941 7840 2354
1 Dependability Create route 2960 7892 2370
1 Dependability Remove route 2894 7708 2314
1 Dependability Add switch to route 2948 7860 2360
1 Dependability Remove switch from route 2934 7820 2348
1 Dependability Set switch failed 2941 7840 2354
1 Dependability Set switch operational 2941 7840 2354
2 Dependability (A) Usual mix 5459 14440 4336
2 Dependability (B) Depend. stress mix 5266 13800 4152
2 Dependability (C) VirtSw. stress mix 5911 15760 4732
2 Dependability (D) mix 5461 14424 4334
2 Dependability (E) mix 5911 15760 4732
2 Dependability Create switch 5919 15780 4738
2 Dependability Create segment 5911 15760 4732
2 Dependability Connect tract elements 5911 15760 4732
2 Dependability Disconnect track elements 5911 15760 4732
2 Dependability Create route 5930 15812 4748
2 Dependability Remove route 5878 15668 4704
2 Dependability Add switch to route 5918 15780 4738
2 Dependability Remove switch from route 5904 15740 4726
2 Dependability Set switch failed 5911 15760 4732
2 Dependability Set switch operational 5911 15760 4732
4 Dependability (A) Usual mix 12908 34340 10310
4 Dependability (B) Depend. stress mix 13667 36420 10942
4 Dependability (C) VirtSw. stress mix 13171 35120 10544
4 Dependability (D) mix 12966 34484 10356
4 Dependability (E) mix 13171 35120 10544
4 Dependability Create switch 13179 35140 10550
4 Dependability Create segment 13171 35120 10544
4 Dependability Connect tract elements 13171 35120 10544
4 Dependability Disconnect track elements 13171 35120 10544
4 Dependability Create route 13190 35172 10560
4 Dependability Remove route 13138 35028 10516
4 Dependability Add switch to route 13178 35140 10550
4 Dependability Remove switch from route 13164 35100 10538
4 Dependability Set switch failed 13171 35120 10544
4 Dependability Set switch operational 13171 35120 10544
8 Dependability (A) Usual mix 33788 89820 26962
8 Dependability (B) Depend. stress mix 34379 91420 27450
8 Dependability (C) VirtSw. stress mix 35101 93600 28096
8 Dependability (D) mix 34469 91744 27542
8 Dependability (E) mix 35101 93600 28096
8 Dependability Create switch 35109 93620 28102
8 Dependability Create segment 35101 93600 28096
8 Dependability Connect tract elements 35101 93600 28096
8 Dependability Disconnect track elements 35101 93600 28096
8 Dependability Create route 35120 93652 28112
8 Dependability Remove route 34522 91948 27600
8 Dependability Add switch to route 35108 93620 28102
8 Dependability Remove switch from route 35094 93580 28090
8 Dependability Set switch failed 35101 93600 28096
8 Dependability Set switch operational 35101 93600 28096
16 Dependability (A) Usual mix 69975 186100 55862
16 Dependability (B) Depend. stress mix 71588 190620 57226
16 Dependability (C) VirtSw. stress mix 72436 193160 57980
16 Dependability (D) mix 69795 185564 55704
16 Dependability (E) mix 72436 193160 57980
16 Dependability Create switch 72444 193180 57986
16 Dependability Create segment 72436 193160 57980
16 Dependability Connect tract elements 72436 193160 57980
16 Dependability Disconnect track elements 72436 193160 57980
16 Dependability Create route 72455 193212 57996
16 Dependability Remove route 71857 191508 57484
16 Dependability Add switch to route 72443 193180 57986
16 Dependability Remove switch from route 72429 193140 57974
16 Dependability Set switch failed 72436 193160 57980
16 Dependability Set switch operational 72436 193160 57980
16 VirtualSwitch (A) Usual mix 505 324 505
16 VirtualSwitch (B) Depend. stress mix 520 338 520
16 VirtualSwitch (C) VirtSw. stress mix 494 311 494
16 VirtualSwitch (D) mix 506 327 506
16 VirtualSwitch (E) mix 495 349 495
16 VirtualSwitch Create switch 496 325 496
16 VirtualSwitch Create segment 495 325 495
16 VirtualSwitch Connect tract elements 495 325 495
16 VirtualSwitch Disconnect track elements 495 325 495
16 VirtualSwitch Create route 495 325 495
16 VirtualSwitch Remove route 495 325 495
16 VirtualSwitch Add switch to route 495 325 495
16 VirtualSwitch Remove switch from route 495 325 495
16 VirtualSwitch Set switch failed 494 325 494
16 VirtualSwitch Set switch operational 496 327 496
32 VirtualSwitch (A) Usual mix 1050 713 1050
32 VirtualSwitch (B) Depend. stress mix 1065 727 1065
32 VirtualSwitch (C) VirtSw. stress mix 1039 693 1039
32 VirtualSwitch (D) mix 1051 707 1051
32 VirtualSwitch (E) mix 1040 731 1040
32 VirtualSwitch Create switch 1041 708 1041
32 VirtualSwitch Create segment 1040 708 1040
32 VirtualSwitch Connect tract elements 1040 708 1040
32 VirtualSwitch Disconnect track elements 1040 708 1040
32 VirtualSwitch Create route 1040 708 1040
32 VirtualSwitch Remove route 1040 708 1040
32 VirtualSwitch Add switch to route 1040 708 1040
32 VirtualSwitch Remove switch from route 1040 708 1040
32 VirtualSwitch Set switch failed 1039 707 1039
32 VirtualSwitch Set switch operational 1041 710 1041
64 VirtualSwitch (A) Usual mix 2070 1373 2070
64 VirtualSwitch (B) Depend. stress mix 2085 1389 2085
64 VirtualSwitch (C) VirtSw. stress mix 2059 1359 2059
64 VirtualSwitch (D) mix 2071 1373 2071
64 VirtualSwitch (E) mix 2060 1394 2060
64 VirtualSwitch Create switch 2061 1370 2061
64 VirtualSwitch Create segment 2060 1370 2060
64 VirtualSwitch Connect tract elements 2060 1370 2060
64 VirtualSwitch Disconnect track elements 2060 1370 2060
64 VirtualSwitch Create route 2060 1370 2060
64 VirtualSwitch Remove route 2060 1370 2060
64 VirtualSwitch Add switch to route 2060 1370 2060
64 VirtualSwitch Remove switch from route 2060 1370 2060
64 VirtualSwitch Set switch failed 2059 1368 2059
64 VirtualSwitch Set switch operational 2061 1371 2061
128 VirtualSwitch (A) Usual mix 4259 2845 4259
128 VirtualSwitch (B) Depend. stress mix 4274 2856 4274
128 VirtualSwitch (C) VirtSw. stress mix 4248 2828 4248
128 VirtualSwitch (D) mix 4260 2837 4260
128 VirtualSwitch (E) mix 4249 2863 4249
128 VirtualSwitch Create switch 4250 2842 4250
128 VirtualSwitch Create segment 4249 2841 4249
128 VirtualSwitch Connect tract elements 4249 2841 4249
128 VirtualSwitch Disconnect track elements 4249 2840 4249
128 VirtualSwitch Create route 4249 2841 4249
128 VirtualSwitch Remove route 4249 2841 4249
128 VirtualSwitch Add switch to route 4249 2841 4249
128 VirtualSwitch Remove switch from route 4249 2841 4249
128 VirtualSwitch Set switch failed 4248 2839 4248
128 VirtualSwitch Set switch operational 4250 2841 4250
256 VirtualSwitch (A) Usual mix 8771 5875 8771
256 VirtualSwitch (B) Depend. stress mix 8786 5886 8786
256 VirtualSwitch (C) VirtSw. stress mix 8760 5852 8760
256 VirtualSwitch (D) mix 8772 5871 8772
256 VirtualSwitch (E) mix 8761 5896 8761
256 VirtualSwitch Create switch 8762 5870 8762
256 VirtualSwitch Create segment 8761 5869 8761
256 VirtualSwitch Connect tract elements 8761 5870 8761
256 VirtualSwitch Disconnect track elements 8761 5869 8761
256 VirtualSwitch Create route 8761 5869 8761
256 VirtualSwitch Remove route 8761 5869 8761
256 VirtualSwitch Add switch to route 8761 5869 8761
256 VirtualSwitch Remove switch from route 8761 5869 8761
256 VirtualSwitch Set switch failed 8760 5868 8760
256 VirtualSwitch Set switch operational 8762 5870 8762

We make sure that each experiment resulted in the same number of target model elements when executed with the same source model and modification mix.

incremental_target_model_statistics_by_experiment <- trainbenchmark_log %>%
  filter(modificationMix != 'none' &
           checkpoint == 'after' &
           category == 'target') %>%
  group_by(modelSize, transformationCase, modificationMix, experiment, rerun, variable) %>%
  summarize(value = first(value)) %>%
  mutate(variable = paste0('actual_', variable)) %>%
  spread(variable, value) %>%
  ungroup()

bad_incremental_experiments <- incremental_target_model_statistics_by_experiment %>%
  inner_join(incremental_target_model_statistics,
    by = c('modelSize', 'transformationCase', 'modificationMix')) %>%
  filter(actual_rootCount != target_rootCount |
           actual_count != target_count |
           actual_referenceCount != target_referenceCount |
           actual_attributeCount != target_attributeCount)


if (nrow(bad_incremental_experiments) != 0) {
  print(bad_incremental_experiments)
  stop("Unexpected incremental transformation results")
} else {
  message("All correct")
}
## All correct

We may see that every incremental transformation resulted in the expected number of target elements.

Execution time (RQ2 and RQ3)

Data wrangling

We define a helper function for collecting execution times from the batch and incremental versions of experiments.

RenameExperiment <- function(df) {
  df %>% mutate(experiment = gsub("-(batch|incremental)", "", experiment))
}

First execution (RQ2)

We will “formally” treat model query and first execution as two modification mixes, which simplifies our data frames. They will be shown on the same plots as the incremental sychronization times, anyway.

We collect the execution time of the model query in the first (also known as “batch” in the logs) execution. This is relatively simple, as all experiments contain a modelQuery checkpoint.

modelQuery <- trainbenchmark_log %>%
  filter(modificationMix == 'none' &
           variable == 'duration' &
           checkpoint == 'modelQuery') %>%
  mutate(modificationMix='modelQuery') %>%
  RenameExperiment()

We extract the first execution time of the hand-written VIATRA transformations, too. Only the hand-written transformations have an execute checkpoint in the log.

execution_viatra <- trainbenchmark_log %>%
  filter(modificationMix == 'none' &
           variable == 'duration' &
           checkpoint == 'execute') %>%
  mutate(modificationMix='execute') %>%
  RenameExperiment()

Extracting the first run of the ViewModel transformations is a bit more involved, as different steps were logged separately. We simply sum their durations.

execution_viewmodel <- trainbenchmark_log %>%
  filter(modificationMix == 'none' &
           variable == 'duration' &
           checkpoint %in% c('pt2tExecute', 'pt2tRete', 's2ptExecute', 's2ptRete')) %>%
  group_by(transformationCase, experiment, rerun, category, variable, modelSize) %>%
  summarize(checkpoint='execute', modificationMix='execute', value=sum(value)) %>%
  ungroup() %>%
  RenameExperiment()

Incremental transformations (RQ3)

The execution time of change-driven synchronization is split between the modelModification (propagation of source model changes trough the RETE net) and synchronization (firing of change-driven transformation rules) phases. We sum the two durations.

incremental <- trainbenchmark_log %>%
  filter(modificationMix != 'none' &
           variable == 'duration' &
           checkpoint %in% c('synchronization', 'modelModification')) %>%
  group_by(transformationCase, experiment, rerun, category, variable, modelSize, modificationMix) %>%
  summarize(checkpoint='synchronization', value=sum(value)) %>%
  ungroup() %>%
  RenameExperiment()

Putting it together

We bind the data frames from the previous two sections, and join them to the target and source model statistics. Then we prepare for creating the plots as follows:

  • The total model size is the geometric mean of the number of source and target model objects. This measure was selected because it can indicate scaleability in both case studies considered.
  • Only the median of the execution times is kept.
  • Execution times smaller than 1 ms are replaced with 1 ms so that a log-log plot can be drawn. Zero execution times would lead to NaN values after taking their logarithm.
durations_plot <- rbind(incremental, modelQuery, execution_viatra, execution_viewmodel) %>%
  inner_join(target_model_statistics, by = c('transformationCase', 'modelSize')) %>%
  inner_join(source_model_statistics, by = c('modelSize')) %>%
  mutate(total_count = sqrt(source_count * target_count)) %>%
  group_by(modelSize, transformationCase, modificationMix, experiment) %>%
  summarize(total_count = median(total_count), value = median(value)) %>%
  mutate(value = ifelse(value < 1, 1, value))

We add some factor labels in order to generate appropriate legends in the plots.

durations_plot$modificationMix <- ModificationMixFactor(durations_plot$modificationMix)
durations_plot$transformationCase <- TransformationCaseFactor(durations_plot$transformationCase)
durations_plot$experiment <- ExperimentFactor(durations_plot$experiment)
durations_plot <- durations_plot %>%
  arrange(transformationCase, modelSize, modificationMix, experiment)

A large table can be assembled for viewing by spreading the three experiments side by side. Note that different modification mixes were evaluated on different virtual machines, so executing times are only comparable within a single modification mix.

durations_table <- durations_plot %>%
  spread(experiment, value) %>%
  arrange(modificationMix, transformationCase, modelSize)
colnames(durations_table)[1:4] <- c("Scale factor", "Case study", "Modification mix", "Total size")
knitr::kable(durations_table, format='markdown') %>% cat(sep = '\n')
Scale factor Case study Modification mix Total size Our approach Source-reactive VIATRA Trace-reactive VIATRA
1 Dependability Initial query 1726.897 13.0 15.0 12.0
2 Dependability Initial query 3471.675 17.0 21.0 17.5
4 Dependability Initial query 7754.071 30.0 34.0 29.5
8 Dependability Initial query 20704.794 72.0 77.0 69.0
16 Dependability Initial query 42774.536 157.0 179.0 161.0
16 VirtualSwitch Initial query 3535.987 496.0 500.0 500.0
32 VirtualSwitch Initial query 7196.594 1115.5 1124.5 1129.5
64 VirtualSwitch Initial query 14473.970 2713.0 2722.5 2720.0
128 VirtualSwitch Initial query 29725.280 6478.0 6539.0 6501.5
256 VirtualSwitch Initial query 61041.622 15056.5 15083.0 15112.5
1 Dependability Initial transformation 1726.897 687.5 13.0 13.0
2 Dependability Initial transformation 3471.675 1436.0 26.0 27.0
4 Dependability Initial transformation 7754.071 3533.5 62.0 64.0
8 Dependability Initial transformation 20704.794 10787.0 180.0 184.0
16 Dependability Initial transformation 42774.536 26707.5 459.0 476.0
16 VirtualSwitch Initial transformation 3535.987 258.0 7.0 8.0
32 VirtualSwitch Initial transformation 7196.594 472.5 17.0 18.0
64 VirtualSwitch Initial transformation 14473.970 906.0 42.0 44.0
128 VirtualSwitch Initial transformation 29725.280 1937.0 124.0 119.0
256 VirtualSwitch Initial transformation 61041.622 4370.5 407.0 357.0
1 Dependability (A) Usual mix 1726.897 1189.0 16.0 16.5
2 Dependability (A) Usual mix 3471.675 2204.0 15.0 15.0
4 Dependability (A) Usual mix 7754.071 5051.0 15.0 16.0
8 Dependability (A) Usual mix 20704.794 31582.5 74.0 73.0
16 Dependability (A) Usual mix 42774.536 97159.0 217.0 216.0
16 VirtualSwitch (A) Usual mix 3535.987 49.0 9.0 10.0
32 VirtualSwitch (A) Usual mix 7196.594 56.0 9.0 10.0
64 VirtualSwitch (A) Usual mix 14473.970 60.0 10.0 11.0
128 VirtualSwitch (A) Usual mix 29725.280 72.0 8.0 11.0
256 VirtualSwitch (A) Usual mix 61041.622 94.0 9.0 13.0
1 Dependability (B) Depend. stress mix 1726.897 1517.0 16.0 16.0
2 Dependability (B) Depend. stress mix 3471.675 3947.5 26.0 25.0
4 Dependability (B) Depend. stress mix 7754.071 6816.0 14.0 14.0
8 Dependability (B) Depend. stress mix 20704.794 34707.5 71.0 69.0
16 Dependability (B) Depend. stress mix 42774.536 75205.5 132.5 131.5
16 VirtualSwitch (B) Depend. stress mix 3535.987 15.0 3.0 3.0
32 VirtualSwitch (B) Depend. stress mix 7196.594 16.0 3.0 3.0
64 VirtualSwitch (B) Depend. stress mix 14473.970 16.0 3.0 4.0
128 VirtualSwitch (B) Depend. stress mix 29725.280 22.0 4.0 4.0
256 VirtualSwitch (B) Depend. stress mix 61041.622 17.0 4.0 4.0
1 Dependability (C) VirtSw. stress mix 1726.897 21.0 1.0 1.0
2 Dependability (C) VirtSw. stress mix 3471.675 29.0 1.0 1.0
4 Dependability (C) VirtSw. stress mix 7754.071 48.0 1.0 1.0
8 Dependability (C) VirtSw. stress mix 20704.794 87.0 1.0 1.5
16 Dependability (C) VirtSw. stress mix 42774.536 156.0 2.0 1.5
16 VirtualSwitch (C) VirtSw. stress mix 3535.987 70.0 8.0 9.0
32 VirtualSwitch (C) VirtSw. stress mix 7196.594 80.0 8.0 9.0
64 VirtualSwitch (C) VirtSw. stress mix 14473.970 83.0 9.0 10.0
128 VirtualSwitch (C) VirtSw. stress mix 29725.280 101.5 9.0 11.0
256 VirtualSwitch (C) VirtSw. stress mix 61041.622 155.0 11.0 16.5
1 Dependability (D) mix 1726.897 1417.0 17.0 17.0
2 Dependability (D) mix 3471.675 2371.5 16.0 15.0
4 Dependability (D) mix 7754.071 4521.0 16.0 16.0
8 Dependability (D) mix 20704.794 18343.5 47.0 46.0
16 Dependability (D) mix 42774.536 76439.5 220.0 218.0
16 VirtualSwitch (D) mix 3535.987 61.5 9.0 10.0
32 VirtualSwitch (D) mix 7196.594 66.0 7.5 9.0
64 VirtualSwitch (D) mix 14473.970 70.0 8.0 10.0
128 VirtualSwitch (D) mix 29725.280 93.0 7.0 11.0
256 VirtualSwitch (D) mix 61041.622 130.0 9.0 15.5
1 Dependability (E) mix 1726.897 1.0 1.0 1.0
2 Dependability (E) mix 3471.675 1.0 1.0 1.0
4 Dependability (E) mix 7754.071 1.0 1.0 1.0
8 Dependability (E) mix 20704.794 1.0 1.0 1.0
16 Dependability (E) mix 42774.536 1.0 1.0 1.0
16 VirtualSwitch (E) mix 3535.987 36.0 18.0 18.0
32 VirtualSwitch (E) mix 7196.594 37.5 17.0 17.0
64 VirtualSwitch (E) mix 14473.970 47.0 21.0 21.0
128 VirtualSwitch (E) mix 29725.280 56.0 17.0 17.0
256 VirtualSwitch (E) mix 61041.622 84.0 19.0 20.0
1 Dependability Create switch 1726.897 20.0 1.0 1.0
2 Dependability Create switch 3471.675 50.0 1.0 1.0
4 Dependability Create switch 7754.071 109.0 1.0 1.0
8 Dependability Create switch 20704.794 350.0 1.0 1.0
16 Dependability Create switch 42774.536 756.0 1.0 1.0
16 VirtualSwitch Create switch 3535.987 1.0 1.0 1.0
32 VirtualSwitch Create switch 7196.594 1.0 1.0 1.0
64 VirtualSwitch Create switch 14473.970 1.0 1.0 1.0
128 VirtualSwitch Create switch 29725.280 1.0 1.0 1.0
256 VirtualSwitch Create switch 61041.622 1.5 1.0 1.0
1 Dependability Create segment 1726.897 1.0 1.0 1.0
2 Dependability Create segment 3471.675 1.0 1.0 1.0
4 Dependability Create segment 7754.071 1.0 1.0 1.0
8 Dependability Create segment 20704.794 1.0 1.0 1.0
16 Dependability Create segment 42774.536 1.0 1.0 1.0
16 VirtualSwitch Create segment 3535.987 1.0 1.0 1.0
32 VirtualSwitch Create segment 7196.594 1.0 1.0 1.0
64 VirtualSwitch Create segment 14473.970 1.0 1.0 1.0
128 VirtualSwitch Create segment 29725.280 1.0 1.0 1.0
256 VirtualSwitch Create segment 61041.622 1.0 1.0 1.0
1 Dependability Connect tract elements 1726.897 1.0 1.0 1.0
2 Dependability Connect tract elements 3471.675 1.0 1.0 1.0
4 Dependability Connect tract elements 7754.071 1.0 1.0 1.0
8 Dependability Connect tract elements 20704.794 1.0 1.0 1.0
16 Dependability Connect tract elements 42774.536 1.0 1.0 1.0
16 VirtualSwitch Connect tract elements 3535.987 1.0 1.0 1.0
32 VirtualSwitch Connect tract elements 7196.594 1.0 1.0 1.0
64 VirtualSwitch Connect tract elements 14473.970 1.0 1.0 1.0
128 VirtualSwitch Connect tract elements 29725.280 21.0 1.0 1.0
256 VirtualSwitch Connect tract elements 61041.622 1.0 1.0 1.0
1 Dependability Disconnect track elements 1726.897 1.0 1.0 1.0
2 Dependability Disconnect track elements 3471.675 1.0 1.0 1.0
4 Dependability Disconnect track elements 7754.071 1.0 1.0 1.0
8 Dependability Disconnect track elements 20704.794 1.0 1.0 1.0
16 Dependability Disconnect track elements 42774.536 1.0 1.0 1.0
16 VirtualSwitch Disconnect track elements 3535.987 1.0 1.0 1.0
32 VirtualSwitch Disconnect track elements 7196.594 1.0 1.0 1.0
64 VirtualSwitch Disconnect track elements 14473.970 1.0 1.0 1.0
128 VirtualSwitch Disconnect track elements 29725.280 14.0 1.0 1.0
256 VirtualSwitch Disconnect track elements 61041.622 30.0 1.0 1.0
1 Dependability Create route 1726.897 43.5 1.0 1.0
2 Dependability Create route 3471.675 98.5 1.0 1.0
4 Dependability Create route 7754.071 300.5 1.0 1.0
8 Dependability Create route 20704.794 891.5 1.0 1.0
16 Dependability Create route 42774.536 1429.5 1.0 1.0
16 VirtualSwitch Create route 3535.987 1.0 1.0 1.0
32 VirtualSwitch Create route 7196.594 1.0 1.0 1.0
64 VirtualSwitch Create route 14473.970 1.0 1.0 1.0
128 VirtualSwitch Create route 29725.280 1.0 1.0 1.0
256 VirtualSwitch Create route 61041.622 1.0 1.0 1.0
1 Dependability Remove route 1726.897 101.5 3.0 3.0
2 Dependability Remove route 3471.675 152.5 2.0 3.0
4 Dependability Remove route 7754.071 357.5 3.0 3.0
8 Dependability Remove route 20704.794 10297.0 28.0 28.0
16 Dependability Remove route 42774.536 21001.0 59.0 58.0
16 VirtualSwitch Remove route 3535.987 1.0 1.0 1.0
32 VirtualSwitch Remove route 7196.594 1.0 1.0 1.0
64 VirtualSwitch Remove route 14473.970 1.0 1.0 1.0
128 VirtualSwitch Remove route 29725.280 1.0 1.0 1.0
256 VirtualSwitch Remove route 61041.622 1.0 1.0 1.0
1 Dependability Add switch to route 1726.897 7.0 1.0 1.0
2 Dependability Add switch to route 3471.675 25.0 1.0 1.0
4 Dependability Add switch to route 7754.071 49.0 1.0 1.0
8 Dependability Add switch to route 20704.794 83.0 1.0 1.0
16 Dependability Add switch to route 42774.536 182.5 1.0 1.0
16 VirtualSwitch Add switch to route 3535.987 1.0 1.0 1.0
32 VirtualSwitch Add switch to route 7196.594 1.0 1.0 1.0
64 VirtualSwitch Add switch to route 14473.970 1.0 1.0 1.0
128 VirtualSwitch Add switch to route 29725.280 1.0 1.0 1.0
256 VirtualSwitch Add switch to route 61041.622 1.0 1.0 1.0
1 Dependability Remove switch from route 1726.897 21.0 1.0 1.0
2 Dependability Remove switch from route 3471.675 33.5 1.0 1.0
4 Dependability Remove switch from route 7754.071 75.0 1.0 1.0
8 Dependability Remove switch from route 20704.794 216.0 2.0 2.0
16 Dependability Remove switch from route 42774.536 492.5 3.0 3.0
16 VirtualSwitch Remove switch from route 3535.987 1.0 1.0 1.0
32 VirtualSwitch Remove switch from route 7196.594 1.0 1.0 1.0
64 VirtualSwitch Remove switch from route 14473.970 1.0 1.0 1.0
128 VirtualSwitch Remove switch from route 29725.280 1.0 1.0 1.0
256 VirtualSwitch Remove switch from route 61041.622 1.0 1.0 1.0
1 Dependability Set switch failed 1726.897 13.0 1.0 1.0
2 Dependability Set switch failed 3471.675 15.5 1.0 1.0
4 Dependability Set switch failed 7754.071 30.5 1.0 1.0
8 Dependability Set switch failed 20704.794 86.5 1.0 1.0
16 Dependability Set switch failed 42774.536 207.5 1.0 1.0
16 VirtualSwitch Set switch failed 3535.987 8.0 1.0 1.0
32 VirtualSwitch Set switch failed 7196.594 15.0 1.0 1.0
64 VirtualSwitch Set switch failed 14473.970 20.0 1.0 1.0
128 VirtualSwitch Set switch failed 29725.280 33.0 1.0 2.0
256 VirtualSwitch Set switch failed 61041.622 79.5 1.0 5.0
1 Dependability Set switch operational 1726.897 7.0 1.0 1.0
2 Dependability Set switch operational 3471.675 11.0 1.0 1.0
4 Dependability Set switch operational 7754.071 18.0 1.0 1.0
8 Dependability Set switch operational 20704.794 52.0 1.0 1.0
16 Dependability Set switch operational 42774.536 120.0 1.0 1.0
16 VirtualSwitch Set switch operational 3535.987 7.0 1.0 1.0
32 VirtualSwitch Set switch operational 7196.594 7.0 1.0 1.0
64 VirtualSwitch Set switch operational 14473.970 10.0 1.0 1.0
128 VirtualSwitch Set switch operational 29725.280 1.0 1.0 1.0
256 VirtualSwitch Set switch operational 61041.622 28.0 1.0 1.0

Plots

Let use define some helper functions for making publication-quality plots.

scientific_10 <- function (x) {
  parse(text=gsub("1e", " 10^", scales::scientific_format()(x)))
}

DurationsPlot <- function (df) {
  ggplot(df, aes(x = total_count, y = value, color=experiment, shape=experiment)) +
    geom_point(size = 2) +
    geom_line() +
    scale_x_continuous(name = "Model size = sqrt(#source objects * #target object)",
                       trans = "log",
                       limits = c(1000, 100000),
                       breaks = c(1, 10, 100, 1000, 10000, 100000),
                       label=scientific_10) +
    scale_y_continuous(name = "Execution time (ms)",
                       trans = 'log',
                       limits = c(1, 150000),
                       breaks = c(1, 10, 100, 1000, 10000, 100000),
                       label=scientific_10) +
    facet_grid(transformationCase~modificationMix) +
    scale_color_brewer(type='qual', palette=6, name = "Transformation") +
    scale_shape_manual(values=c(1, 4, 3), name="Transformation") +
    theme_bw() +
    theme(legend.position='bottom', legend.box.spacing = unit(c(0, 0, 0, 0), 'cm'))
}

We split the plots into three blocks due to their size.

durations_plot %>% filter(as.numeric(modificationMix) < 8) %>% DurationsPlot()

durations_plot %>% filter(as.numeric(modificationMix) >= 8 & as.numeric(modificationMix) < 13) %>% DurationsPlot()

durations_plot %>% filter(as.numeric(modificationMix) >= 13) %>% DurationsPlot()

Instrumented first-run transformations (RQ1)

In order to analyze first run behavior in depth, ViewModel was instrumented to log each phase of first run execution separately. These phases are

As the RETE constrution times are usually much shorter than the firing time, we add them to the firing times and compare the overall execution times of the Source2PartialTarget and PartialTarget2Target phases.

instrumented_plot <- trainbenchmark_log %>%
  filter(modificationMix == 'none' &
           variable == 'duration' &
           checkpoint %in% c('pt2tExecute', 'pt2tRete', 's2ptExecute', 's2ptRete')) %>%
  mutate(checkpoint = gsub('Execute|Rete', '', checkpoint)) %>%
  group_by(transformationCase, experiment, rerun, category, variable, modelSize, checkpoint, modificationMix) %>%
  summarize(value=sum(value)) %>%
  ungroup() %>%
  inner_join(target_model_statistics, by = c('transformationCase', 'modelSize')) %>%
  inner_join(source_model_statistics, by = c('modelSize')) %>%
  mutate(total_count = sqrt(source_count * target_count)) %>%
  group_by(modelSize, transformationCase, modificationMix, experiment, checkpoint) %>%
  summarize(total_count = median(total_count), value = median(value)) %>%
  mutate(value = ifelse(value < 1, 1, value)) %>%
  ungroup()

instrumented_plot$transformationCase <- TransformationCaseFactor(instrumented_plot$transformationCase)
instrumented_plot$checkpoint <- factor(as.factor(instrumented_plot$checkpoint),
                                    levels = c('s2pt', 'pt2t'),
                                    labels = c('S2PT', 'PT2T'))
show_instrumented_plot <- instrumented_plot %>%
  select(-c(modificationMix, experiment)) %>%
  spread(checkpoint, value)
colnames(show_instrumented_plot) <- c('Scale factor', 'Case study', 'Total size', 'PT2T duration', 'S2PT duration')

knitr::kable(show_instrumented_plot, format='markdown') %>% cat(sep = '\n')
Scale factor Case study Total size PT2T duration S2PT duration
1 Dependability 1726.897 393.0 294.5
2 Dependability 3471.675 827.5 610.5
4 Dependability 7754.071 1890.0 1653.0
8 Dependability 20704.794 5441.0 5360.0
16 Dependability 42774.536 12291.0 14386.0
16 VirtualSwitch 3535.987 173.0 85.0
32 VirtualSwitch 7196.594 356.0 116.5
64 VirtualSwitch 14473.970 731.0 176.0
128 VirtualSwitch 29725.280 1620.0 317.0
256 VirtualSwitch 61041.622 3713.0 654.0
ggplot(instrumented_plot, aes(x = total_count, y = value, color=checkpoint, shape=checkpoint)) +
  geom_point(size=3.5) +
  geom_line() +
  scale_x_continuous(name = "Model size",
                     trans = "log",
                     limits = c(1000, 100000),
                     breaks = c(1, 10, 100, 1000, 10000, 100000),
                     label=scientific_10) +
  scale_y_continuous(name = "Execution time (ms)",
                     trans = 'log',
                     limits = c(1, 150000),
                     breaks = c(1, 10, 100, 1000, 10000, 100000),
                     label=scientific_10) +
  facet_grid(transformationCase~.) +
  scale_color_brewer(type='qual', palette=6, name = "Execution step") +
  scale_shape_manual(values=c(1, 4), name="Execution step") +
  theme_bw() +
  theme(legend.position='bottom', legend.box.spacing = unit(c(0, 0, 0, 0), 'cm'))