1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
/*******************************************************************************
* Copyright (c) 2011 protos software gmbh (http://www.protos.de).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* CONTRIBUTORS:
* Eyrak Pean (initial contribution)
* Juergen Haug
*
*******************************************************************************/
package org.eclipse.etrice.generator.gnuplot
import com.google.inject.Inject
import org.eclipse.etrice.core.common.base.Annotation
import org.eclipse.etrice.core.common.base.IntLiteral
import org.eclipse.etrice.core.common.base.KeyValue
import org.eclipse.etrice.core.common.base.RealLiteral
import org.eclipse.etrice.core.common.base.StringLiteral
import org.eclipse.etrice.core.genmodel.etricegen.Root
import org.eclipse.etrice.core.genmodel.etricegen.SubSystemInstance
import org.eclipse.etrice.generator.base.io.IGeneratorFileIO
import org.eclipse.etrice.generator.generic.RoomExtensions
import com.google.inject.Singleton
@Singleton
class GnuplotScriptGenerator {
@Inject
IGeneratorFileIO fileIo
@Inject
extension RoomExtensions roomExtensions
def doGenerate(Root root) {
if (root.subSystemInstances.empty)
return;
// TODO: warning more than one ssi
val ssi = root.subSystemInstances.head
if(!ssi.subSystemClass.annotations.exists[a |a.type.name == "Gnuplot"])
return;
val path = ssi.subSystemClass.getGenerationTargetPath
val infoPath = ssi.subSystemClass.generationInfoPath
try {
fileIo.generateFile("Generating gnuplot script for subsystem " + ssi.name, path, infoPath,
"/gnuplot/main.data.csv-script.plt", ssi.generatePlotScript)
fileIo.generateFile("Generating gnuplot launch configuration", path, infoPath,
"/gnuplot/create_gnuplot.launch", gnuPlotLaunchFile)
} catch (Exception e) {
//e.printStackTrace
}
}
def protected gnuPlotLaunchFile() '''
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LAUNCH_CONFIGURATION_BUILD_SCOPE" value="${none}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${system_path:gnuplot}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="${project_loc}/src-gen/gnuplot/main.data.csv-script.plt"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${project_loc}"/>
</launchConfiguration>
'''
def protected getAttribute(Annotation anno, String name) {
anno.attributes.findFirst[attr|attr.key == name]
}
def protected asString(KeyValue kv) {
if (kv.value instanceof StringLiteral)
(kv.value as StringLiteral).value
else
null
}
def protected asReal(KeyValue kv) {
if (kv.value instanceof RealLiteral)
(kv.value as RealLiteral).value
else if (kv.value instanceof IntLiteral)
(kv.value as IntLiteral).value as double
else
null
}
def protected asInteger(KeyValue kv) {
if (kv.value instanceof IntLiteral)
(kv.value as IntLiteral).value
else
null
}
def protected generatePlotScript(SubSystemInstance ssi) {
// TODO: warn if more than one GnuPlot annotation
val plotAnnotation = ssi.subSystemClass.annotations.filter [ a |
a.type.name == "Gnuplot"
].head
val defaultFontsize = 10
// TODO: error checking
val format = plotAnnotation?.getAttribute("format")?.asString
val outputfile = plotAnnotation?.getAttribute("outputfile")?.asString
val width = plotAnnotation?.getAttribute("width")?.asInteger
val height = plotAnnotation?.getAttribute("height")?.asInteger
val fontsize = plotAnnotation?.getAttribute("fontsize")?.asInteger ?: defaultFontsize
val graphAnnotations = ssi.subSystemClass.annotations.filter [ a |
a.type.name == "GnuplotGraph"
].toList
'''
#!/gnuplot
# Color Brewer set1 5-set
set linetype 1 lc rgb '#e41a1c' lw 1
set linetype 2 lc rgb '#377eb8' lw 1
set linetype 3 lc rgb '#4daf4a' lw 1
set linetype 4 lc rgb '#984ea3' lw 1
set linetype 5 lc rgb '#ff7f00' lw 1
set linetype cycle 5
cd 'log'
set datafile separator comma
set terminal «format» size «width»,«height» font ",«fontsize»" background "white"
set output '«outputfile»'
set size 1,1
set multiplot layout «graphAnnotations.size»,1
set grid
show grid
set format y "% 5.3f"
«var i = 0»
«FOR a : graphAnnotations»
«ssi.generateGraph(a, i++, graphAnnotations.size)»
«ENDFOR»
unset multiplot
unset output
'''
}
def protected generateGraph(SubSystemInstance ssi, Annotation graph, int index, int total) {
// TODO: handle multiple paths in the same graph
val paths = graph.getAttribute("paths")?.asString
// TODO: take interval from physical thread associated with actor instance instead of annotation attribute
val interval = graph.getAttribute("interval")?.asInteger ?: 20
val xtics = graph.getAttribute("xtics")?.asReal ?: 100
val mxtics = graph.getAttribute("mxtics")?.asInteger ?: 4
val ymin = graph.getAttribute("ymin")?.asReal
val ymax = graph.getAttribute("ymax")?.asReal
val vertOrigin = ((total - (index + 1)) as double) / total
val vertSize = 1.0F / total
'''
set yrange [«ymin ?: "*"» : «ymax ?: "*"»]
set xtics rotate «xtics»
set mxtics «mxtics»
set ylabel
set xlabel "time (ms)"
timeInMs(x) = «interval» * x
set origin 0,«vertOrigin»
set size 1,«vertSize»
plot 'main.data.csv' using (timeInMs(column(1))):(column("«paths»")) with lines
'''
}
}
|