source: Jenkinsfile@ 3489ea6

ADT ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 3489ea6 was 9824500, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Fixed email generation in Jenkins

  • Property mode set to 100644
File size: 15.3 KB
Line 
1#!groovy
2
3import groovy.transform.Field
4
5//===========================================================================================================
6// Main loop of the compilation
7//===========================================================================================================
8
9// Globals
10BuildDir = null
11SrcDir = null
12Settings = null
13Tools = null
14
15// Local variables
16def err = null
17def log_needed = false
18
19currentBuild.result = "SUCCESS"
20
21try {
22 node {
23 //Wrap build to add timestamp to command line
24 wrap([$class: 'TimestamperBuildWrapper']) {
25 Settings = prepare_build()
26 }
27 }
28
29 node(Settings.Architecture.node) {
30 //Wrap build to add timestamp to command line
31 wrap([$class: 'TimestamperBuildWrapper']) {
32 BuildDir = pwd tmp: true
33 SrcDir = pwd tmp: false
34 currentBuild.description = "${currentBuild.description} on ${env.NODE_NAME}"
35
36 Tools.Clean()
37
38 Tools.Checkout()
39
40 build()
41
42 test()
43
44 benchmark()
45
46 build_doc()
47
48 publish()
49 }
50 }
51}
52
53//If an exception is caught we need to change the status and remember to
54//attach the build log to the email
55catch (Exception caughtError) {
56 // Store the result of the build log
57 currentBuild.result = "FAILURE"
58
59 // An error has occured, the build log is relevent
60 log_needed = true
61
62 // rethrow error later
63 err = caughtError
64
65 // print the error so it shows in the log
66 echo err.toString()
67}
68
69finally {
70 //Send email with final results if this is not a full build
71 email(log_needed)
72
73 echo 'Build Completed'
74
75 /* Must re-throw exception to propagate error */
76 if (err) {
77 throw err
78 }
79}
80//===========================================================================================================
81// Main compilation routines
82//===========================================================================================================
83def build() {
84 debug = true
85 release = Settings.RunAllTests || Settings.RunBenchmark
86 Tools.BuildStage('Build : configure', true) {
87 // Configure must be run inside the tree
88 dir (SrcDir) {
89 // Generate the necessary build files
90 sh './autogen.sh'
91 }
92
93 // Build outside of the src tree to ease cleaning
94 dir (BuildDir) {
95 //Configure the compilation (Output is not relevant)
96 //Use the current directory as the installation target so nothing escapes the sandbox
97 //Also specify the compiler by hand
98 targets=""
99 if( Settings.RunAllTests || Settings.RunBenchmark ) {
100 targets="--with-target-hosts='host:debug,host:nodebug'"
101 } else {
102 targets="--with-target-hosts='host:debug'"
103 }
104
105 ast = Settings.NewAST ? "--enable-new-ast" : "--disable-new-ast"
106
107 sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} AR=gcc-ar RANLIB=gcc-ranlib ${targets} ${ast} --quiet --prefix=${BuildDir}"
108
109 // Configure libcfa
110 sh 'make -j 8 --no-print-directory configure-libcfa'
111 }
112 }
113
114 Tools.BuildStage('Build : cfa-cpp', true) {
115 // Build outside of the src tree to ease cleaning
116 dir (BuildDir) {
117 // Build driver
118 sh 'make -j 8 --no-print-directory -C driver'
119
120 // Build translator
121 sh 'make -j 8 --no-print-directory -C src'
122 }
123 }
124
125 Tools.BuildStage('Build : libcfa(debug)', debug) {
126 // Build outside of the src tree to ease cleaning
127 dir (BuildDir) {
128 sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-debug"
129 }
130 }
131
132 Tools.BuildStage('Build : libcfa(nodebug)', release) {
133 // Build outside of the src tree to ease cleaning
134 dir (BuildDir) {
135 sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-nodebug"
136 }
137 }
138
139 Tools.BuildStage('Build : install', true) {
140 // Build outside of the src tree to ease cleaning
141 dir (BuildDir) {
142 sh "make -j 8 --no-print-directory install"
143 }
144 }
145}
146
147def test() {
148 try {
149 // Print potential limits before testing
150 // in case jenkins messes with them
151 sh 'free -h'
152 sh 'ulimit -a'
153
154 Tools.BuildStage('Test: short', !Settings.RunAllTests) {
155 dir (BuildDir) {
156 //Run the tests from the tests directory
157 sh "make --no-print-directory -C tests archiveerrors=${BuildDir}/tests/crashes/short"
158 }
159 }
160
161 Tools.BuildStage('Test: full', Settings.RunAllTests) {
162 dir (BuildDir) {
163 //Run the tests from the tests directory
164 sh """make --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=yes archiveerrors=${BuildDir}/tests/crashes/full-debug"""
165 sh """make --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=no archiveerrors=${BuildDir}/tests/crashes/full-nodebug"""
166 }
167 }
168 }
169 catch (Exception err) {
170 echo "Archiving core dumps"
171 dir (BuildDir) {
172 def exists = fileExists 'tests/crashes'
173 if( exists ) {
174 sh """${SrcDir}/tools/jenkins/archive-gen.sh"""
175 archiveArtifacts artifacts: "tests/crashes/**/*,lib/**/lib*.so*,setup.sh", fingerprint: true
176 }
177 }
178 throw err
179 }
180}
181
182def benchmark() {
183 Tools.BuildStage('Benchmark', Settings.RunBenchmark) {
184 dir (BuildDir) {
185 //Append bench results
186 sh "make --no-print-directory -C benchmark jenkins arch=${Settings.Architecture.name}"
187 }
188 }
189}
190
191def build_doc() {
192 Tools.BuildStage('Documentation', Settings.BuildDocumentation) {
193 dir ('doc/user') {
194 make_doc()
195 }
196
197 dir ('doc/refrat') {
198 make_doc()
199 }
200 }
201}
202
203def publish() {
204 Tools.BuildStage('Publish', true) {
205
206 if( Settings.Publish && !Settings.RunBenchmark ) { echo 'No results to publish!!!' }
207
208 def groupCompile = new PlotGroup('Compilation', 'duration (s) - lower is better', true)
209 def groupConcurrency = new PlotGroup('Concurrency', 'duration (n) - lower is better', false)
210
211 //Then publish the results
212 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile' , groupCompile , false, 'Compilation')
213 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile.diff' , groupCompile , true , 'Compilation (relative)')
214 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch' , groupConcurrency, false, 'Context Switching')
215 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch.diff' , groupConcurrency, true , 'Context Switching (relative)')
216 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex' , groupConcurrency, false, 'Mutual Exclusion')
217 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex.diff' , groupConcurrency, true , 'Mutual Exclusion (relative)')
218 do_plot(Settings.RunBenchmark && Settings.Publish, 'scheduling' , groupConcurrency, false, 'Internal and External Scheduling')
219 do_plot(Settings.RunBenchmark && Settings.Publish, 'scheduling.diff', groupConcurrency, true , 'Internal and External Scheduling (relative)')
220 }
221}
222
223//===========================================================================================================
224//Routine responsible of sending the email notification once the build is completed
225//===========================================================================================================
226//Standard build email notification
227def email(boolean log) {
228 node {
229 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
230 //Configurations for email format
231 echo 'Notifying users of result'
232
233 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase()
234 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}"
235 def email_body = """<p>This is an automated email from the Jenkins build machine. It was
236 generated because of a git hooks/post-receive script following
237 a ref change which was pushed to the C\u2200 repository.</p>
238
239 <p>- Status --------------------------------------------------------------</p>
240
241 <p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p>
242 <p>Check console output at ${env.BUILD_URL} to view the results.</p>
243 """ + Tools.GitLogMessage()
244
245 def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca"
246
247 if( Settings && !Settings.Silent ) {
248 //send email notification
249 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log
250 } else {
251 echo "Would send email to: ${email_to}"
252 echo "With title: ${email_subject}"
253 echo "Content: \n${email_body}"
254 }
255 }
256}
257
258//===========================================================================================================
259// Helper classes/variables/routines
260//===========================================================================================================
261//Description of a compiler (Must be serializable since pipelines are persistent)
262class CC_Desc implements Serializable {
263 public String name
264 public String CXX
265 public String CC
266 public String lto
267
268 CC_Desc(String name, String CXX, String CC, String lto) {
269 this.name = name
270 this.CXX = CXX
271 this.CC = CC
272 this.lto = lto
273 }
274}
275
276//Description of an architecture (Must be serializable since pipelines are persistent)
277class Arch_Desc implements Serializable {
278 public String name
279 public String flags
280 public String node
281
282 Arch_Desc(String name, String flags, String node) {
283 this.name = name
284 this.flags = flags
285 this.node = node
286 }
287}
288
289class BuildSettings implements Serializable {
290 public final CC_Desc Compiler
291 public final Arch_Desc Architecture
292 public final Boolean NewAST
293 public final Boolean RunAllTests
294 public final Boolean RunBenchmark
295 public final Boolean BuildDocumentation
296 public final Boolean Publish
297 public final Boolean Silent
298 public final Boolean IsSandbox
299 public final String DescLong
300 public final String DescShort
301
302 public String GitNewRef
303 public String GitOldRef
304
305 BuildSettings(java.util.Collections$UnmodifiableMap param, String branch) {
306 switch( param.Compiler ) {
307 case 'gcc-9':
308 this.Compiler = new CC_Desc('gcc-9', 'g++-9', 'gcc-9', '-flto=auto')
309 break
310 case 'gcc-8':
311 this.Compiler = new CC_Desc('gcc-8', 'g++-8', 'gcc-8', '-flto=auto')
312 break
313 case 'gcc-7':
314 this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7', '-flto=auto')
315 break
316 case 'gcc-6':
317 this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6', '-flto=auto')
318 break
319 case 'gcc-5':
320 this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5', '-flto=auto')
321 break
322 case 'gcc-4.9':
323 this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9', '-flto=auto')
324 break
325 case 'clang':
326 this.Compiler = new CC_Desc('clang', 'clang++-10', 'gcc-9', '-flto=thin -flto-jobs=0')
327 break
328 default :
329 error "Unhandled compiler : ${cc}"
330 }
331
332 switch( param.Architecture ) {
333 case 'x64':
334 this.Architecture = new Arch_Desc('x64', '--host=x86_64', 'x64')
335 break
336 case 'x86':
337 this.Architecture = new Arch_Desc('x86', '--host=i386', 'x86')
338 break
339 default :
340 error "Unhandled architecture : ${arch}"
341 }
342
343 this.IsSandbox = (branch == "jenkins-sandbox")
344 this.NewAST = param.NewAST
345 this.RunAllTests = param.RunAllTests
346 this.RunBenchmark = param.RunBenchmark
347 this.BuildDocumentation = param.BuildDocumentation
348 this.Publish = param.Publish
349 this.Silent = param.Silent
350
351 def full = param.RunAllTests ? " (Full)" : ""
352 this.DescShort = "${ this.Compiler.name }:${ this.Architecture.name }${full}"
353
354 final ast = this.NewAST ? "New AST" : "Old AST"
355 this.DescLong = """Compiler : ${ this.Compiler.name } (${ this.Compiler.CXX }/${ this.Compiler.CC })
356AST Version : ${ ast.toString() }
357Architecture : ${ this.Architecture.name }
358Arc Flags : ${ this.Architecture.flags }
359Run All Tests : ${ this.RunAllTests.toString() }
360Run Benchmark : ${ this.RunBenchmark.toString() }
361Build Documentation : ${ this.BuildDocumentation.toString() }
362Publish : ${ this.Publish.toString() }
363Silent : ${ this.Silent.toString() }
364"""
365
366 this.GitNewRef = ''
367 this.GitOldRef = ''
368 }
369}
370
371class PlotGroup implements Serializable {
372 public String name
373 public String unit
374 public boolean log
375
376 PlotGroup(String name, String unit, boolean log) {
377 this.name = name
378 this.unit = unit
379 this.log = log
380 }
381}
382
383def prepare_build() {
384 // prepare the properties
385 properties ([ \
386 buildDiscarder(logRotator( \
387 artifactDaysToKeepStr: '', \
388 artifactNumToKeepStr: '', \
389 daysToKeepStr: '730', \
390 numToKeepStr: '1000' \
391 )), \
392 [$class: 'ParametersDefinitionProperty', \
393 parameterDefinitions: [ \
394 [$class: 'ChoiceParameterDefinition', \
395 description: 'Which compiler to use', \
396 name: 'Compiler', \
397 choices: 'gcc-9\ngcc-8\ngcc-7\ngcc-6\ngcc-5\ngcc-4.9\nclang', \
398 defaultValue: 'gcc-8', \
399 ], \
400 [$class: 'ChoiceParameterDefinition', \
401 description: 'The target architecture', \
402 name: 'Architecture', \
403 choices: 'x64\nx86', \
404 defaultValue: 'x64', \
405 ], \
406 [$class: 'BooleanParameterDefinition', \
407 description: 'If true, build compiler using new AST', \
408 name: 'NewAST', \
409 defaultValue: true, \
410 ], \
411 [$class: 'BooleanParameterDefinition', \
412 description: 'If false, only the quick test suite is ran', \
413 name: 'RunAllTests', \
414 defaultValue: false, \
415 ], \
416 [$class: 'BooleanParameterDefinition', \
417 description: 'If true, jenkins also runs benchmarks', \
418 name: 'RunBenchmark', \
419 defaultValue: false, \
420 ], \
421 [$class: 'BooleanParameterDefinition', \
422 description: 'If true, jenkins also builds documentation', \
423 name: 'BuildDocumentation', \
424 defaultValue: true, \
425 ], \
426 [$class: 'BooleanParameterDefinition', \
427 description: 'If true, jenkins also publishes results', \
428 name: 'Publish', \
429 defaultValue: false, \
430 ], \
431 [$class: 'BooleanParameterDefinition', \
432 description: 'If true, jenkins will not send emails', \
433 name: 'Silent', \
434 defaultValue: false, \
435 ], \
436 ],
437 ]])
438
439 // It's unfortunate but it looks like we need to checkout the entire repo just to get
440 // - the pretty git printer
441 // - Jenkins.tools
442 checkout scm
443
444 Tools = load "Jenkins/tools.groovy"
445
446 final settings = new BuildSettings(params, env.BRANCH_NAME)
447
448 currentBuild.description = settings.DescShort
449 echo settings.DescLong
450
451 return settings
452}
453
454def make_doc() {
455 def err = null
456 try {
457 sh 'make clean > /dev/null'
458 sh 'make > /dev/null 2>&1'
459 }
460 catch (Exception caughtError) {
461 err = caughtError //rethrow error later
462 sh 'cat build/*.log'
463 }
464 finally {
465 if (err) throw err // Must re-throw exception to propagate error
466 }
467}
468
469def do_plot(boolean new_data, String file, PlotGroup group, boolean relative, String title) {
470
471 if(new_data) {
472 echo "Publishing new data"
473 }
474
475 def series = new_data ? [[
476 file: "${file}.csv",
477 exclusionValues: '',
478 displayTableFlag: false,
479 inclusionFlag: 'OFF',
480 url: ''
481 ]] : [];
482
483 echo "file is ${BuildDir}/benchmark/${file}.csv, group ${group}, title ${title}"
484 dir("${BuildDir}/benchmark/") {
485 plot csvFileName: "cforall-${env.BRANCH_NAME}-${file}.csv",
486 csvSeries: series,
487 group: "${group.name}",
488 title: "${title}",
489 style: 'lineSimple',
490 exclZero: false,
491 keepRecords: false,
492 logarithmic: !relative && group.log,
493 numBuilds: '120',
494 useDescr: true,
495 yaxis: group.unit,
496 yaxisMaximum: '',
497 yaxisMinimum: ''
498 }
499}
Note: See TracBrowser for help on using the repository browser.