source: Jenkinsfile @ 32ab519

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

Jenkins now generates a setup.sh script when archiving test failures.
The script can be run to ease reproduction in gdb.

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