source: Jenkinsfile@ 7f9968ad

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 7f9968ad was c862fae, checked in by Thierry Delisle <tdelisle@…>, 6 years ago

Fixed typo in Jenkinsfile and added abort test to test libcfa archival

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