source: Jenkinsfile@ 5b544a6

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

fixed scheduling benchmarks in jenkins to use consistent file naming

  • Property mode set to 100644
File size: 16.3 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} ${targets} --quiet"
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
161def test() {
162 try {
163 build_stage('Test: short', !Settings.RunAllTests) {
164 dir (BuildDir) {
165 //Run the tests from the tests directory
166 sh "make --no-print-directory -C tests archiveerrors=${BuildDir}/tests/crashes/short"
167 }
168 }
169
170 build_stage('Test: full', Settings.RunAllTests) {
171 dir (BuildDir) {
172 //Run the tests from the tests directory
173 sh """make --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=yes archiveerrors=${BuildDir}/tests/crashes/full-debug"""
174 sh """make --no-print-directory -C tests timeouts="--timeout=600 --global-timeout=14400" all-tests debug=no archiveerrors=${BuildDir}/tests/crashes/full-nodebug"""
175 }
176 }
177 }
178 catch (Exception err) {
179 echo "Archiving core dumps"
180 dir (BuildDir) {
181 archiveArtifacts artifacts: "tests/crashes/**/*", fingerprint: true
182 }
183 throw err
184 }
185}
186
187def benchmark() {
188 build_stage('Benchmark', Settings.RunBenchmark) {
189 dir (BuildDir) {
190 //Append bench results
191 sh "make --no-print-directory -C benchmark jenkins arch=${Settings.Architecture.name}"
192 }
193 }
194}
195
196def build_doc() {
197 build_stage('Documentation', Settings.BuildDocumentation) {
198 dir ('doc/user') {
199 make_doc()
200 }
201
202 dir ('doc/refrat') {
203 make_doc()
204 }
205 }
206}
207
208def publish() {
209 build_stage('Publish', true) {
210
211 if( Settings.Publish && !Settings.RunBenchmark ) { echo 'No results to publish!!!' }
212
213 def groupCompile = new PlotGroup('Compilation', 'duration (s) - lower is better', true)
214 def groupConcurrency = new PlotGroup('Concurrency', 'duration (n) - lower is better', false)
215
216 //Then publish the results
217 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile' , groupCompile , false, 'Compilation')
218 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile.diff' , groupCompile , true , 'Compilation (relative)')
219 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch' , groupConcurrency, false, 'Context Switching')
220 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch.diff' , groupConcurrency, true , 'Context Switching (relative)')
221 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex' , groupConcurrency, false, 'Mutual Exclusion')
222 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex.diff' , groupConcurrency, true , 'Mutual Exclusion (relative)')
223 do_plot(Settings.RunBenchmark && Settings.Publish, 'scheduling' , groupConcurrency, false, 'Internal and External Scheduling')
224 do_plot(Settings.RunBenchmark && Settings.Publish, 'scheduling.diff', groupConcurrency, true , 'Internal and External Scheduling (relative)')
225 }
226}
227
228//===========================================================================================================
229//Routine responsible of sending the email notification once the build is completed
230//===========================================================================================================
231@NonCPS
232def SplitLines(String text) {
233 def list = []
234
235 text.eachLine {
236 list += it
237 }
238
239 return list
240}
241
242def GitLogMessage() {
243 if (!Settings || !Settings.GitOldRef || !Settings.GitNewRef) return "\nERROR retrieveing git information!\n"
244
245 def oldRef = Settings.GitOldRef
246 def newRef = Settings.GitNewRef
247
248 def revText = sh(returnStdout: true, script: "git rev-list ${oldRef}..${newRef}").trim()
249 def revList = SplitLines( revText )
250
251 def gitUpdate = ""
252 revList.each { rev ->
253 def type = sh(returnStdout: true, script: "git cat-file -t ${rev}").trim()
254 gitUpdate = gitUpdate + " via ${rev} (${type})"
255 }
256
257 def rev = oldRef
258 def type = sh(returnStdout: true, script: "git cat-file -t ${rev}").trim()
259 gitUpdate = gitUpdate + " from ${rev} (${type})"
260
261 def gitLog = sh(returnStdout: true, script: "git rev-list --format=short ${oldRef}...${newRef}").trim()
262
263 def gitDiff = sh(returnStdout: true, script: "git diff --stat --color ${newRef} ${oldRef}").trim()
264 gitDiff = gitDiff.replace('[32m', '<span style="color: #00AA00;">')
265 gitDiff = gitDiff.replace('[31m', '<span style="color: #AA0000;">')
266 gitDiff = gitDiff.replace('[m', '</span>')
267
268 return """
269<pre>
270The branch ${env.BRANCH_NAME} has been updated.
271${gitUpdate}
272</pre>
273
274<p>Check console output at ${env.BUILD_URL} to view the results.</p>
275
276<p>- Status --------------------------------------------------------------</p>
277
278<p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p>
279
280<p>- Log -----------------------------------------------------------------</p>
281
282<pre>
283${gitLog}
284</pre>
285
286<p>-----------------------------------------------------------------------</p>
287<pre>
288Summary of changes:
289${gitDiff}
290</pre>
291"""
292}
293
294//Standard build email notification
295def email(boolean log) {
296 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
297 //Configurations for email format
298 echo 'Notifying users of result'
299
300 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase()
301 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}"
302 def email_body = """<p>This is an automated email from the Jenkins build machine. It was
303generated because of a git hooks/post-receive script following
304a ref change which was pushed to the C\u2200 repository.</p>
305""" + GitLogMessage()
306
307 def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca"
308
309 if( Settings && !Settings.Silent ) {
310 //send email notification
311 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log
312 } else {
313 echo "Would send email to: ${email_to}"
314 echo "With title: ${email_subject}"
315 echo "Content: \n${email_body}"
316 }
317}
318
319//===========================================================================================================
320// Helper classes/variables/routines
321//===========================================================================================================
322//Description of a compiler (Must be serializable since pipelines are persistent)
323class CC_Desc implements Serializable {
324 public String name
325 public String CXX
326 public String CC
327
328 CC_Desc(String name, String CXX, String CC) {
329 this.name = name
330 this.CXX = CXX
331 this.CC = CC
332 }
333}
334
335//Description of an architecture (Must be serializable since pipelines are persistent)
336class Arch_Desc implements Serializable {
337 public String name
338 public String flags
339 public String node
340
341 Arch_Desc(String name, String flags, String node) {
342 this.name = name
343 this.flags = flags
344 this.node = node
345 }
346}
347
348class BuildSettings implements Serializable {
349 public final CC_Desc Compiler
350 public final Arch_Desc Architecture
351 public final Boolean RunAllTests
352 public final Boolean RunBenchmark
353 public final Boolean BuildDocumentation
354 public final Boolean Publish
355 public final Boolean Silent
356 public final Boolean IsSandbox
357 public final String DescLong
358 public final String DescShort
359
360 public String GitNewRef
361 public String GitOldRef
362
363 BuildSettings(java.util.Collections$UnmodifiableMap param, String branch) {
364 switch( param.Compiler ) {
365 case 'gcc-9':
366 this.Compiler = new CC_Desc('gcc-9', 'g++-9', 'gcc-9')
367 break
368 case 'gcc-8':
369 this.Compiler = new CC_Desc('gcc-8', 'g++-8', 'gcc-8')
370 break
371 case 'gcc-7':
372 this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7')
373 break
374 case 'gcc-6':
375 this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6')
376 break
377 case 'gcc-5':
378 this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5')
379 break
380 case 'gcc-4.9':
381 this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9')
382 break
383 case 'clang':
384 this.Compiler = new CC_Desc('clang', 'clang++-6.0', 'gcc-6')
385 break
386 default :
387 error "Unhandled compiler : ${cc}"
388 }
389
390 switch( param.Architecture ) {
391 case 'x64':
392 this.Architecture = new Arch_Desc('x64', '--host=x86_64', 'x64')
393 break
394 case 'x86':
395 this.Architecture = new Arch_Desc('x86', '--host=i386', 'x86')
396 break
397 default :
398 error "Unhandled architecture : ${arch}"
399 }
400
401 this.IsSandbox = (branch == "jenkins-sandbox")
402 this.RunAllTests = param.RunAllTests
403 this.RunBenchmark = param.RunBenchmark
404 this.BuildDocumentation = param.BuildDocumentation
405 this.Publish = param.Publish
406 this.Silent = param.Silent
407
408 def full = param.RunAllTests ? " (Full)" : ""
409 this.DescShort = "${ this.Compiler.name }:${ this.Architecture.name }${full}"
410
411 this.DescLong = """Compiler : ${ this.Compiler.name } (${ this.Compiler.CXX }/${ this.Compiler.CC })
412Architecture : ${ this.Architecture.name }
413Arc Flags : ${ this.Architecture.flags }
414Run All Tests : ${ this.RunAllTests.toString() }
415Run Benchmark : ${ this.RunBenchmark.toString() }
416Build Documentation : ${ this.BuildDocumentation.toString() }
417Publish : ${ this.Publish.toString() }
418Silent : ${ this.Silent.toString() }
419"""
420
421 this.GitNewRef = ''
422 this.GitOldRef = ''
423 }
424}
425
426class PlotGroup implements Serializable {
427 public String name
428 public String unit
429 public boolean log
430
431 PlotGroup(String name, String unit, boolean log) {
432 this.name = name
433 this.unit = unit
434 this.log = log
435 }
436}
437
438def prepare_build() {
439 // prepare the properties
440 properties ([ \
441 [$class: 'ParametersDefinitionProperty', \
442 parameterDefinitions: [ \
443 [$class: 'ChoiceParameterDefinition', \
444 description: 'Which compiler to use', \
445 name: 'Compiler', \
446 choices: 'gcc-9\ngcc-8\ngcc-7\ngcc-6\ngcc-5\ngcc-4.9\nclang', \
447 defaultValue: 'gcc-8', \
448 ], \
449 [$class: 'ChoiceParameterDefinition', \
450 description: 'The target architecture', \
451 name: 'Architecture', \
452 choices: 'x64\nx86', \
453 defaultValue: 'x64', \
454 ], \
455 [$class: 'BooleanParameterDefinition', \
456 description: 'If false, only the quick test suite is ran', \
457 name: 'RunAllTests', \
458 defaultValue: false, \
459 ], \
460 [$class: 'BooleanParameterDefinition', \
461 description: 'If true, jenkins also runs benchmarks', \
462 name: 'RunBenchmark', \
463 defaultValue: false, \
464 ], \
465 [$class: 'BooleanParameterDefinition', \
466 description: 'If true, jenkins also builds documentation', \
467 name: 'BuildDocumentation', \
468 defaultValue: true, \
469 ], \
470 [$class: 'BooleanParameterDefinition', \
471 description: 'If true, jenkins also publishes results', \
472 name: 'Publish', \
473 defaultValue: false, \
474 ], \
475 [$class: 'BooleanParameterDefinition', \
476 description: 'If true, jenkins will not send emails', \
477 name: 'Silent', \
478 defaultValue: false, \
479 ], \
480 ],
481 ]])
482
483 // It's unfortunate but it looks like we need to checkout the entire repo just to get the pretty git printer
484 checkout scm
485
486 final settings = new BuildSettings(params, env.BRANCH_NAME)
487
488 currentBuild.description = settings.DescShort
489 echo settings.DescLong
490
491 return settings
492}
493
494def build_stage(String name, boolean run, Closure block ) {
495 StageName = name
496 echo " -------- ${StageName} -------- "
497 if(run) {
498 stage(name, block)
499 } else {
500 stage(name) { Utils.markStageSkippedForConditional(STAGE_NAME) }
501 }
502}
503
504def make_doc() {
505 def err = null
506 try {
507 sh 'make clean > /dev/null'
508 sh 'make > /dev/null 2>&1'
509 }
510 catch (Exception caughtError) {
511 err = caughtError //rethrow error later
512 sh 'cat build/*.log'
513 }
514 finally {
515 if (err) throw err // Must re-throw exception to propagate error
516 }
517}
518
519def do_plot(boolean new_data, String file, PlotGroup group, boolean relative, String title) {
520
521 if(new_data) {
522 echo "Publishing new data"
523 }
524
525 def series = new_data ? [[
526 file: "${file}.csv",
527 exclusionValues: '',
528 displayTableFlag: false,
529 inclusionFlag: 'OFF',
530 url: ''
531 ]] : [];
532
533 echo "file is ${BuildDir}/benchmark/${file}.csv, group ${group}, title ${title}"
534 dir("${BuildDir}/benchmark/") {
535 plot csvFileName: "cforall-${env.BRANCH_NAME}-${file}.csv",
536 csvSeries: series,
537 group: "${group.name}",
538 title: "${title}",
539 style: 'lineSimple',
540 exclZero: false,
541 keepRecords: false,
542 logarithmic: !relative && group.log,
543 numBuilds: '120',
544 useDescr: true,
545 yaxis: group.unit,
546 yaxisMaximum: '',
547 yaxisMinimum: ''
548 }
549}
Note: See TracBrowser for help on using the repository browser.