source: Jenkinsfile @ bf22bc6

arm-ehjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-expr
Last change on this file since bf22bc6 was bf22bc6, checked in by Thierry Delisle <tdelisle@…>, 19 months ago

Disable lto since it remove necessary side effects

  • Property mode set to 100644
File size: 16.5 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"
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        public String lto
328
329        CC_Desc(String name, String CXX, String CC, String lto) {
330                this.name = name
331                this.CXX = CXX
332                this.CC  = CC
333                this.lto = lto
334        }
335}
336
337//Description of an architecture (Must be serializable since pipelines are persistent)
338class Arch_Desc implements Serializable {
339        public String name
340        public String flags
341        public String node
342
343        Arch_Desc(String name, String flags, String node) {
344                this.name  = name
345                this.flags = flags
346                this.node  = node
347        }
348}
349
350class BuildSettings implements Serializable {
351        public final CC_Desc Compiler
352        public final Arch_Desc Architecture
353        public final Boolean RunAllTests
354        public final Boolean RunBenchmark
355        public final Boolean BuildDocumentation
356        public final Boolean Publish
357        public final Boolean Silent
358        public final Boolean IsSandbox
359        public final String DescLong
360        public final String DescShort
361
362        public String GitNewRef
363        public String GitOldRef
364
365        BuildSettings(java.util.Collections$UnmodifiableMap param, String branch) {
366                switch( param.Compiler ) {
367                        case 'gcc-9':
368                                this.Compiler = new CC_Desc('gcc-9', 'g++-9', 'gcc-9', '-flto=auto')
369                        break
370                        case 'gcc-8':
371                                this.Compiler = new CC_Desc('gcc-8', 'g++-8', 'gcc-8', '-flto=auto')
372                        break
373                        case 'gcc-7':
374                                this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7', '-flto=auto')
375                        break
376                        case 'gcc-6':
377                                this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6', '-flto=auto')
378                        break
379                        case 'gcc-5':
380                                this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5', '-flto=auto')
381                        break
382                        case 'gcc-4.9':
383                                this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9', '-flto=auto')
384                        break
385                        case 'clang':
386                                this.Compiler = new CC_Desc('clang', 'clang++-6.0', 'gcc-6', '-flto=thin -flto-jobs=0')
387                        break
388                        default :
389                                error "Unhandled compiler : ${cc}"
390                }
391
392                switch( param.Architecture ) {
393                        case 'x64':
394                                this.Architecture = new Arch_Desc('x64', '--host=x86_64', 'x64')
395                        break
396                        case 'x86':
397                                this.Architecture = new Arch_Desc('x86', '--host=i386', 'x86')
398                        break
399                        default :
400                                error "Unhandled architecture : ${arch}"
401                }
402
403                this.IsSandbox          = (branch == "jenkins-sandbox")
404                this.RunAllTests        = param.RunAllTests
405                this.RunBenchmark       = param.RunBenchmark
406                this.BuildDocumentation = param.BuildDocumentation
407                this.Publish            = param.Publish
408                this.Silent             = param.Silent
409
410                def full = param.RunAllTests ? " (Full)" : ""
411                this.DescShort = "${ this.Compiler.name }:${ this.Architecture.name }${full}"
412
413                this.DescLong = """Compiler              : ${ this.Compiler.name } (${ this.Compiler.CXX }/${ this.Compiler.CC })
414Architecture            : ${ this.Architecture.name }
415Arc Flags               : ${ this.Architecture.flags }
416Run All Tests           : ${ this.RunAllTests.toString() }
417Run Benchmark           : ${ this.RunBenchmark.toString() }
418Build Documentation     : ${ this.BuildDocumentation.toString() }
419Publish                 : ${ this.Publish.toString() }
420Silent                  : ${ this.Silent.toString() }
421"""
422
423                this.GitNewRef = ''
424                this.GitOldRef = ''
425        }
426}
427
428class PlotGroup implements Serializable {
429        public String name
430        public String unit
431        public boolean log
432
433        PlotGroup(String name, String unit, boolean log) {
434                this.name = name
435                this.unit = unit
436                this.log = log
437        }
438}
439
440def prepare_build() {
441        // prepare the properties
442        properties ([                                                                                                   \
443                [$class: 'ParametersDefinitionProperty',                                                                \
444                        parameterDefinitions: [                                                                         \
445                                [$class: 'ChoiceParameterDefinition',                                           \
446                                        description: 'Which compiler to use',                                   \
447                                        name: 'Compiler',                                                                       \
448                                        choices: 'gcc-9\ngcc-8\ngcc-7\ngcc-6\ngcc-5\ngcc-4.9\nclang',                                   \
449                                        defaultValue: 'gcc-8',                                                          \
450                                ],                                                                                              \
451                                [$class: 'ChoiceParameterDefinition',                                           \
452                                        description: 'The target architecture',                                 \
453                                        name: 'Architecture',                                                           \
454                                        choices: 'x64\nx86',                                                            \
455                                        defaultValue: 'x64',                                                            \
456                                ],                                                                                              \
457                                [$class: 'BooleanParameterDefinition',                                                  \
458                                        description: 'If false, only the quick test suite is ran',              \
459                                        name: 'RunAllTests',                                                            \
460                                        defaultValue: false,                                                            \
461                                ],                                                                                              \
462                                [$class: 'BooleanParameterDefinition',                                                  \
463                                        description: 'If true, jenkins also runs benchmarks',           \
464                                        name: 'RunBenchmark',                                                           \
465                                        defaultValue: false,                                                            \
466                                ],                                                                                              \
467                                [$class: 'BooleanParameterDefinition',                                                  \
468                                        description: 'If true, jenkins also builds documentation',              \
469                                        name: 'BuildDocumentation',                                                     \
470                                        defaultValue: true,                                                             \
471                                ],                                                                                              \
472                                [$class: 'BooleanParameterDefinition',                                                  \
473                                        description: 'If true, jenkins also publishes results',                 \
474                                        name: 'Publish',                                                                        \
475                                        defaultValue: false,                                                            \
476                                ],                                                                                              \
477                                [$class: 'BooleanParameterDefinition',                                                  \
478                                        description: 'If true, jenkins will not send emails',           \
479                                        name: 'Silent',                                                                         \
480                                        defaultValue: false,                                                            \
481                                ],                                                                                              \
482                        ],
483                ]])
484
485        // It's unfortunate but it looks like we need to checkout the entire repo just to get the pretty git printer
486        checkout scm
487
488        final settings = new BuildSettings(params, env.BRANCH_NAME)
489
490        currentBuild.description = settings.DescShort
491        echo                       settings.DescLong
492
493        return settings
494}
495
496def build_stage(String name, boolean run, Closure block ) {
497        StageName = name
498        echo " -------- ${StageName} -------- "
499        if(run) {
500                stage(name, block)
501        } else {
502                stage(name) { Utils.markStageSkippedForConditional(STAGE_NAME) }
503        }
504}
505
506def make_doc() {
507        def err = null
508        try {
509                sh 'make clean > /dev/null'
510                sh 'make > /dev/null 2>&1'
511        }
512        catch (Exception caughtError) {
513                err = caughtError //rethrow error later
514                sh 'cat build/*.log'
515        }
516        finally {
517                if (err) throw err // Must re-throw exception to propagate error
518        }
519}
520
521def do_plot(boolean new_data, String file, PlotGroup group, boolean relative, String title) {
522
523        if(new_data) {
524                echo "Publishing new data"
525        }
526
527        def series = new_data ? [[
528                                file: "${file}.csv",
529                                exclusionValues: '',
530                                displayTableFlag: false,
531                                inclusionFlag: 'OFF',
532                                url: ''
533                        ]] : [];
534
535        echo "file is ${BuildDir}/benchmark/${file}.csv, group ${group}, title ${title}"
536        dir("${BuildDir}/benchmark/") {
537                plot csvFileName: "cforall-${env.BRANCH_NAME}-${file}.csv",
538                        csvSeries: series,
539                        group: "${group.name}",
540                        title: "${title}",
541                        style: 'lineSimple',
542                        exclZero: false,
543                        keepRecords: false,
544                        logarithmic: !relative && group.log,
545                        numBuilds: '120',
546                        useDescr: true,
547                        yaxis: group.unit,
548                        yaxisMaximum: '',
549                        yaxisMinimum: ''
550        }
551}
Note: See TracBrowser for help on using the repository browser.