source: Jenkinsfile @ 27b1ca1

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 27b1ca1 was 27b1ca1, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Modified Jenkinsfile to move out some of the helper for later reuse

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