Cicd
Cicd
FABIAN SEGATZ
Abstract
Continuous Integration (CI) techniques are widely adopted in web and ap-
plication development but have received limited attention in the embedded
software domain. This thesis investigates the application of CI techniques
in embedded software development through a case study at Cobolt AB, a
company specializing in optoelectronics. The study aims to identify suitable
CI techniques, assess implementation efforts, and evaluate the impact of CI
adoption in this domain.
A CI service is implemented using Jenkins as the automation server,
following an iterative development and deployment process. The service
incorporates multi-target compilation, automated unit testing, test reporting,
visual CI feedback, and trunk-based development. These techniques prove ef-
fective for embedded software with a modular firmware architecture. However,
automated system testing encounters limitations due to the need for manual
interaction with hardware targets.
Challenges encountered during implementation, such as learning CI tools,
managing build tool dependencies, and addressing manual input requirements
for system testing, are overcome through iterative implementation, distributed
build architecture, and selective test automation. Developers’ resistance to CI
adoption diminishes as they experience the positive impact of the CI service.
CI adoption in the embedded domain brings benefits such as fast bug
detection, increased developer motivation, higher confidence in code quality,
and encouragement for standardization n. No noticeable negative impacts are
observed.
Future research should focus on integrating hardware-in-the-loop simula-
tion systems for comprehensive automated system testing, exploring validation
on multiple hardware targets, and studying the vertical scaling capabilities of
distributed build architectures with Jenkins.
Keywords
Continuous integration, Embedded software development, Modular firmware
architecture, Jenkins, Software quality
ii | Abstract
Sammanfattning | iii
Sammanfattning
Kontinuerlig integration (CI) tekniker används i stor utsträckning inom webb-
och applikationsutveckling, men har fått begränsad uppmärksamhet inom
inbyggd programvarudomän. Denna avhandling undersöker tillämpningen av
CI-tekniker inom inbyggd programvaruutveckling genom en fallstudie vid
Cobolt AB, ett företag specialiserat på optoelektronik. Studien syftar till
att identifiera lämpliga CI-tekniker, bedöma implementeringsinsatser och
utvärdera effekten av CI-användning inom detta område.
En CI-tjänst implementeras med Jenkins som automatiseringsserver, ef-
ter en iterativ utvecklings- och distribueringsprocess. Tjänsten inkluderar
kompilering för flera målenheter, automatiserad enhetstestning, testrapporte-
ring, visuell CI-återkoppling och utveckling baserad på huvudgrenen. Dessa
tekniker visar sig vara effektiva för inbyggd programvara med en modulär
firmware-arkitektur. Dock begränsas automatiserad systemtestning av behovet
av manuell interaktion med hårdvarumål.
Utmaningar som uppstår under implementeringen, såsom att lära sig CI-
verktyg, hantera byggverktygsberoenden och hantera manuella indatakrav
för systemtestning, övervinner genom iterativ implementering, distribuerade
byggarkitekturer och selektiv testautomatisering. Utvecklarnas motstånd mot
CI-användning minskar när de upplever de positiva effekterna av CI-tjänsten.
CI-användning inom inbyggd programvaruutveckling medför fördelar som
snabb upptäckt av fel, ökad utvecklar motivation, högre förtroende för kod-
kvalitet och främjande av standardisering. Inga märkbara negativa effekter
observeras.
Framtida forskning bör fokusera på att integrera hårdvaru-i-loop simule-
ring för omfattande automatiserad systemtestning, utforska validering på flera
hårdvarumål och studera de vertikala skalningsmöjligheterna hos distribuera-
de byggarkitekturer med Jenkins.
Nyckelord
Kontinuerlig integration, Inbyggd programvaruutveckling, Modulär fastvara
arkitektur, Jenkins, Programvarukvalitet
iv | Sammanfattning
Acknowledgments | v
Acknowledgments
I want to express my gratitude to the following individuals whose support and
contributions have been invaluable in the completion of my thesis:
First and foremost, I would like to thank Cyrille, my examiner, for
providing exceptional feedback and asking the right questions during the
project planing phase in December. Your expertise and insightful guidance
have significantly improved the quality of my research. I am grateful for the
opportunity you gave me to explore this subject matter and for your belief in
my abilities.
I am immensely thankful to Han, my academic supervisor, for our regular
meetings. Your dedication, time, and extensive ideas about the direction of
my research have been instrumental in shaping this thesis. Your guidance
and support have been invaluable throughout the entire process. Additionally,
your effective communication has fostered a productive working relationship,
enabling me to navigate through challenges and make significant progress.
To Lukas and Gunnar, my company supervisors, I extend my sincerest
appreciation for trusting me with the project idea and providing support
during its execution. It has been uplifting to feel that my project is genuinely
appreciated. Your guidance and encouragement have motivated me to push
beyond my limits, and I am grateful for the opportunity to work with such
supportive mentors.
I would like to acknowledge the contributions of Per, my colleague. Your
assistance and insightful discussions regarding the build environment have
been immensely helpful. Our lunch talks have provided me with a broader
perspective and helped me overcome various obstacles. Your support and
guidance have made a significant difference, and I am thankful for your
presence throughout this journey.
To my mom and dad, I cannot thank you enough for everything you have
done. Your unwavering love, support, and encouragement have been my
constant source of strength. Your belief in my abilities has been a driving
force behind my achievements, and I am forever grateful for your presence in
my life.
Finally, I also want to thank my Stockholm family, including Marta,
Cate, Lucas, Anders, and Laurène. I am grateful for our thought-provoking
discussions and Friday co-working sessions.
Contents
1 Introduction 1
1.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Goals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 Research Methodology . . . . . . . . . . . . . . . . . . . . . 4
1.6 Delimitations . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.6.1 Focus on Test Execution . . . . . . . . . . . . . . . . 4
1.6.2 Short Term Case Study on CI Service Impact . . . . . 5
1.7 Structure of the Thesis . . . . . . . . . . . . . . . . . . . . . 5
2 Background 7
2.1 Embedded Software Development . . . . . . . . . . . . . . . 7
2.1.1 Characteristics of Embedded Software . . . . . . . . . 8
2.1.2 Modular Firmware Architecture . . . . . . . . . . . . 8
2.1.3 Source Code Management . . . . . . . . . . . . . . . 9
2.1.4 Build Scripts . . . . . . . . . . . . . . . . . . . . . . 11
2.1.5 Build Automation . . . . . . . . . . . . . . . . . . . . 12
2.1.6 Continuous Integration . . . . . . . . . . . . . . . . . 12
2.1.7 Automated Software Testing . . . . . . . . . . . . . . 13
2.2 Cobolt’s Development Environment . . . . . . . . . . . . . . 14
2.2.1 Firmware Architecture — Lysa . . . . . . . . . . . . . 15
2.2.2 Hardware Target — Laser . . . . . . . . . . . . . . . 16
2.2.3 Build System Generator — CMake . . . . . . . . . . 16
2.2.4 Compiler — IAR C/C++ Compiler for ARM . . . . . 16
2.2.5 IDE — IAR Embedded Workbench . . . . . . . . . . 17
2.2.6 Version Control System — Git . . . . . . . . . . . . . 17
2.2.7 Unit Testing Tool — CxxTest . . . . . . . . . . . . . . 17
2.2.8 System Testing Tool — LATE . . . . . . . . . . . . . 18
viii | CONTENTS
3 Methodology 25
3.1 Agile Research Process . . . . . . . . . . . . . . . . . . . . . 26
3.2 Experiment Design . . . . . . . . . . . . . . . . . . . . . . . 27
3.2.1 Single-case Study . . . . . . . . . . . . . . . . . . . . 28
3.2.2 Iterative Implementation Plan . . . . . . . . . . . . . 28
3.2.3 Hardware to be used . . . . . . . . . . . . . . . . . . 29
3.3 Interpretive Research Paradigm . . . . . . . . . . . . . . . . . 30
3.4 Data Collection . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.4.1 Implementation Notebook . . . . . . . . . . . . . . . 31
3.4.2 User Feedback . . . . . . . . . . . . . . . . . . . . . 31
3.4.3 Final Survey . . . . . . . . . . . . . . . . . . . . . . 32
3.4.4 CI Metrics . . . . . . . . . . . . . . . . . . . . . . . 32
3.5 Data Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.5.1 Stage Status . . . . . . . . . . . . . . . . . . . . . . . 34
3.5.2 Stage Duration . . . . . . . . . . . . . . . . . . . . . 35
3.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4 Implementation 37
4.1 Local Jenkins Setup and First Test . . . . . . . . . . . . . . . 37
4.2 Declarative Pipeline for Parallel Firmware Compilation . . . . 38
4.3 Add Unit Testing Stage . . . . . . . . . . . . . . . . . . . . . 38
4.4 Deploying CI Service . . . . . . . . . . . . . . . . . . . . . . 39
4.5 Firmware Download to Target . . . . . . . . . . . . . . . . . 41
4.6 Adding System Testing Stage . . . . . . . . . . . . . . . . . . 42
4.7 Final CI Service . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.8 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
CONTENTS | ix
6 Discussion 69
6.1 CI Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . 69
6.1.1 Multi-target Compilation . . . . . . . . . . . . . . . . 69
6.1.2 Automated Unit Testing . . . . . . . . . . . . . . . . 70
6.1.3 Iterative CI Implementation . . . . . . . . . . . . . . 70
6.1.4 Automated System Testing . . . . . . . . . . . . . . . 71
6.1.5 Distributed Build Architecture . . . . . . . . . . . . . 72
6.1.6 Visual CI Service Feedback . . . . . . . . . . . . . . 72
6.1.7 Test Report in xUnit XML Format . . . . . . . . . . . 72
6.1.8 Trunk-based Development . . . . . . . . . . . . . . . 72
6.2 Efforts for CI Adoption . . . . . . . . . . . . . . . . . . . . . 73
6.2.1 Learn Using the CI Tool . . . . . . . . . . . . . . . . 73
6.2.2 Adress Build Tool Dependencies . . . . . . . . . . . . 73
6.2.3 Adress Manual Input for System Testing . . . . . . . . 74
6.2.4 Improve Visibility of CI Service . . . . . . . . . . . . 74
6.3 Impacts of CI Adoption . . . . . . . . . . . . . . . . . . . . . 74
6.3.1 Fast Bug Detection . . . . . . . . . . . . . . . . . . . 75
6.3.2 Increased Motivation . . . . . . . . . . . . . . . . . . 75
6.3.3 Confidence in Code Quality . . . . . . . . . . . . . . 75
6.3.4 Encourage Standardisation . . . . . . . . . . . . . . . 76
References 81
A Questionnaire 89
B Questionnaire Results 96
LIST OF FIGURES | xi
List of Figures
List of Tables
CI continuous integration
Chapter 1
Introduction
1.1 Background
Cobolt AB∗ is at the very forefront of the industry in the development and man-
ufacturing of high-performance continuous and pulsed lasers. Cobolt AB was
founded in 2000 and is a spin-off of a research project at the laser physics group
from KTH. Today Cobolt AB belongs to the HÜBNER Photonics Group† and
the research department consists of 15 engineers working in a cross-functional
team within CAD, laser-, software- and electronic engineering.
∗
https://www.linkedin.com/company/cobolt-ab (Accessed at
†
09/12/2022) https://www.hubner-photonics.com/ (Accessed at 13/12/2022)
2 | Introduction
1.2 Problem
Firmware projects with modular code architecture are used to allow code
reusability for multiple firmware targets. While this potentially helps to reduce
development time and implement bug fixes and features for many products at
the same time, it can create issues when changes in the code base create bugs
in just a subset of the compilation targets. When not properly tested, it may
be that regression bugs stay undetected. At a later point, when the bug gets
found it might be harder to resolve it compared to when it would have been
done right away.
CI is the state of the art for agile software practices [4]. Especially
with the rising complexity of software systems in the present day, where
many developers collaborate on one product, there must be strategies for
streamlining the integration of code changes. This mostly contains the
execution of automatic tests with every code integration. When working with
modular firmware architectures, CI can be used to automate tests and get
feedback on multiple compilation targets at the same time. Given, that there is
sufficient test coverage, this can help identify regression bugs fast. To the best
of my knowledge, there is no scientific literature available that analyses which
CI techniques are suitable for modular firmware architectures in the embedded
domain.
We would like to answer the question if CI can benefit a project that
involves a modular firmware architecture for embedded systems in a company
like Cobolt. There are no metrics available to evaluate the quality of Cobolt’s
current processes, which makes it complicated to quantitatively measure
improvement that may be achieved with a CI service. Further, it is not clear
which CI techniques are suitable for the development of embedded software
with modular firmware architectures.
Introduction | 3
1.3 Purpose
This degree project, first of all, benefits the company Cobolt AB, which gets
a tailored CI service, that suits their development environment and workflow.
The findings are generalised so that other agents are able to use the thesis report
as a fundament for their own CI implementation.
To comply with ethical challenges that are inherent in research, this project
is aligned with the individual goals for researchers that are described in the
European Code of Conduct for Research Integrity [5]. To take state-of-the-art
research into account a semi-systematic literature study is conducted, that is
carefully analysed and documented. The intellectual contribution of others
are be reported in an appropriate form. This research does not interfere
with personal rights. It does not harm humans and animals nor is it doing
severe damage to the environment. The increased power consumption due to
additional hardware is neglectably small. The intelligence of Cobolt lies in
their laser physics knowledge and not their software development. Thus, there
is no interest conflict in publishing the research outcome to its full extent.
This research addresses goal 9 of the 17 sustainability goals that the United
Nations adopted in their 2030 agenda for sustainable development. Goal 9
is about prospering technological progress. The results of this project are
published on the Diva platform so that anyone can use it to support their
development of CI pipelines and thus help to thrive innovation.
1.4 Goals
This project entails a thorough study of the current state-of-the-art practices for
establishing and examining CI systems in the embedded domain. We explore
how an automatic CI system can be implemented for a modular firmware
architecture used for compiling multiple firmware targets. To achieve this, we
implement a CI service prototype at the company Cobolt. The implementation
effort is reported and analysed. Once the CI service is deployed, we focus on
examining its impact on the current development process. Based on these
considerations, the research questions can be summarised as follows:
1.6 Delimitations
CI services can include a broad variety of different tools and activities. While
it is part of this thesis to identify relevant parts for a CI service for modular
firmware architecture of customizable embedded products, there are some
activities that must be excluded from the beginning because of the time
limitation of this project.
Chapter 2
Background
DevOps is the most widely used practice for software development [2].
Despite the fact that using DevOps methods such as CI and continuous deploy-
ment (CD), automated testing, and monitoring would result in less error-prone
development and improved maintenance of embedded software, those modern
methods of software engineering are still rarely used in embedded software
development. This is because of the unique characteristics and requirements
that the embedded domain poses. Section 2.1 presents an overview of
techniques that can be used in embedded software development. After first
inspecting the characteristics and requirements of embedded software, this
Section explains modular firmware architecture, source code management
(SCM), build scripts, build automation, CI, and automated testing in the
context of embedded software. As in this thesis, implementing CI services is
often done to improve an existing development process. Thus it is important
to understand the existing environment to be able to include and reuse
its components for the CI implementation. Section 2.2 shows the current
development process at Cobolt. All additional tooling that was introduced
to implement the CI service is specified in Section 2.3. Section 2.4 reflects on
related work to this paper.
the operation while isolated from newly implemented features. Branches can
be merged to integrate changes from one branch into another. Depending on
the selected merging strategy, this modifies the history of a branch in different
ways.
There is a wide range of different git-enabled workflows that follow
different branching strategies. Taylor and Taylor [8], name two, that they
identify as typical for embedded software development.
release
cherry-picked
trunk
release
cherry-picked
trunk
featureB
featureA
main
hotfix
release
develop
feature
Figure 2.2: Branching with Git flow (adapted from Driessen [14]
Comparison. Taylor and Taylor suggest using the Git flow strategy for
embedded software projects because it adds an extra layer of security to the
mainline. Especially less-experienced developers do not need to worry about
breaking the trunk branch. Above that, it prevents pollution of the history of
the mainline [8]. However, Driessen, the inventor of the Git flow method,
sees his strategy as dogmatic nowadays. Thus he would not recommend it any
more for projects that do not need to maintain multiple release versions. He
recommends using a simpler strategy, such as the GitHub flow method, which
is, in fact, very similar to the scaled trunk-based approach. Both strategies
have only one long-lived branch; however, GitHub flow is not that explicit
about how long a secondary branch may exist.
“New code is integrated with the current system after no more than
a few hours. When integrating, the system is built from scratch
and all tests must pass or the changes are discarded.” [1]
picks up the change and runs a set of commands to verify the correctness
automatically [15, 16]. This enables faster feedback and less error-prone
testing because a machine will not forget about executing every defined step.
Duvall et al.[17] introduced essential practices for CI, later distilled into
seven cornerstones by Mårtenson et al. [18, Tab. 1]. These include local
code validation before commits, daily commits, automated integration builds
with thorough testing, immediate fixing of broken builds, and ongoing process
improvement through developer engagement.
Taylor and Taylor [8, Fig. 8-1] present a schematic for a typical CI
setup A developer works on a local workstation and has the possibility to
compile, test and debug because all necessary tools and packages are locally
installed. To track the code history and enable collaboration, developers use
a SCM repository. A build machine fetches code changes from the SCM and
automatically executes a set of jobs using some automation tool. For CI, it is
important that the build machine has the same build and test tools installed
as the developer. Further, it is supposed to provide feedback to the developer
about the functional correctness of the code base.
Unit Testing
To conduct unit testing, a small chunk of code, the so-called software under test
(SUT), is compiled and executed as part of a test program. The test program
14 | Background
asserts that an expected condition results from the test and thus verifies the
correct functionality of the SUT [20].
In embedded systems, it is important that the SUT is isolated from its
hardware dependencies to avoid testing hardware and software at the same
time [21]. This can be achieved by writing mock functions to satisfy the
build dependencies, tracing the hardware function calls, or even simulating
hardware response. It is recommended to execute the unit tests off-target [20].
Unit tests are typically written when new functionality is developed,
sometimes even prior to the actual functionality, as in test-driven development
(TDD). After their initial usage, they remain valuable when run as regression
tests [20].
System Testing
System testing — or end-to-end testing as it is called in some literature —
is used to verify the correct system behaviour when a set of conditions is
applied. Its main goal is to test non-functional system requirements (i.e. speed,
security, accuracy, and reliability) and the interaction with different operating
environments [19]. Unlike unit tests, embedded system tests should be
executed on the actual firmware target or at least in a target-like simulation
environment as done in software-in-the-loop simulation (SILS).
System tests on real embedded systems have to be selected carefully. In
safety-critical systems such as fighter jets, a non-acceptable danger for the
environment and humans can result from system failure [22]. But even with
systems that are not safety-critical, system tests can result in self-destruction
[22]. This is an unwanted cost factor, especially for automated system tests, as
the same hardware is supposed to be used many times without being manually
replaced.
its correct behaviour and may run some unit tests. The following sections
describe relevant parts of Cobolt’s development environment, that is used in
the scope of this thesis.
TecModule
LaserModule
Lysa’s folder structure is aligned with its module structure. Figure 2.3
presents a simplified overview of the modules and their interconnections.
<Firmware name> is a placeholder for the name of the respective firmware,
i.e. Capybara. This class specifies the core component, among others by
configuring Property<T> objects. These properties specify a Set/Get
interface for member variables of the different core modules, i.e. Laser-
Module. Properties are the main element for inter-module and module-
hardware communication. The hardware is thereby described in software by
the board class, which specifies and configures the drivers. This structure
allows abstracting the low-level hardware access from the high-level business
logic.
RTOS Embos that Lysa is currently tied to, can only be compiled with the IAR
compiler.
Server Workstation
Coordinator
allocate tasks
Node Node
pipelines, however, are easier to write, read and therefore maintain. They
consist of stages that can get executed sequentially or in parallel on multiple
executors. A stage consists of steps (or tasks) that are executed sequentially.
The execution of a pipeline is called a job and is referenced with a job number,
which allows for keeping a history of previous executions. If a stage in a
pipeline fails, all downstream stages are aborted and considered failing as
well. This is because Jenkins generally considers stages to be dependent on
the output of their predecessors.
Trigger. Jobs can be initiated manually, but typically they are supposed to be
run automatically. Either scheduled or event-based with a trigger, i.e. through
a webhook that signalises a code change in the SCM. Setting up webhooks
usually requires administration rights for the SCM. When those are not given,
Jenkins users have the option to set up a schedule that checks an SCM for code
changes. The pipeline is only running if there are indeed code changes.
Blue Ocean UX. Jenkins is an open-source project, that has many active
developers contributing. This results in Jenkins having a rich ecosystem with
1800+ community plugins. A popular plugin is Blue Ocean∗ , which offers a
modern pipeline visualisation.
In this thesis, it is also not the goal to implement a CI system that includes
all of the possible CI activities. We agree with Rostami et al. [26] who state
that it is very use-case specific which stages are relevant to implement. Our use
case is embedded systems with modular firmware architectures that compile
multiple firmware products. Previous solution proposals do not cover this topic
to the best of our knowledge.
The complexity of CI services varies largely [32]. Some services in the
embedded domain consist of a single pipeline [30]. Others use a two-pipeline
approach [29] to cope with two different compile products that are triggered
independently, but are dependent on each other. Complex services with
manual activities and multiple triggers may require multiple interconnected
pipelines [31]. This thesis presents a fundamental CI service that in fact builds
multiple software products. Yet one pipeline is sufficient since their build is
triggered by the same event. Further, we aim to implement a system with a
small complexity as the cooperating company, Cobolt hasn’t used CI before.
Chapter 3
Methodology
The research process follows an agile approach (as detailed in Section 3.1),
allowing for continuous stakeholder feedback throughout the study. This
approach enables timely data collection in parallel with the implementation
process, making it suitable within the 20-week timeframe of the study.
The agile research process is roughly planned in four iteration stages that
each produce a deployable CI service. Section 3.2 reflects on those stages as
well as the hardware that is required for the CI service prototype.
We answer the research questions according to the interpretative research
paradigm (see Section 3.3).
26 | Methodology
Section 3.4 presents the data collection for this thesis. Qualitative data is
gathered from the experience of the researcher during the implementation, as
well as informal and formal user feedback. The qualitative data is supported
with quantitative data from various CI metrics.
The planned data analysis of the CI metrics is specified in Section 3.5
Collaboration
Investigation Implementation Evaluation
kick-off
The kick-off phase was finalised with the approval of the preliminary time
plan by Han Fu and the signing of the contract with Cobolt. The start date for
the investigation phase was set to be the last week of January 2023.
Principal Server
The principal server is installed inside a virtualisation container on the existing
development server at Cobolt. Since it only acts as a controller and not as
a build agent, it does not require sophisticated hardware. The containerised
environment helps to prevent malicious Jenkins scripts to interfere with the
server itself [42]. From the allocated 900 MB of memory, there were never
more than 250 MB used.
Build Machine
There were two incentives for the selection of the build machine. Firstly, a
machine setup must be selected that allows the execution of all required build
tools (see Section 2.2). Secondly, it is preferred to have a large amount of avail-
able USB slots to attach target hardware test units and debuggers. In general,
selecting hardware is always a trade-off between cost and performance [8].
For this thesis work, an already existing workstation was selected, to not have
extra costs for new hardware. The specs can be obtained from Table 3.2.
Component Description
Operating System Windows 10
Processor Intel I5-10500 @3.10 GHz.
Cores 6
Memory 8 GB
Storage SSD Samsung MZVLQ256HAJD-000H1
USB Slots 9
This section focuses on the various methods used for data collection.
Section 3.4.1 describes how qualitative data is obtained through an under-
standing of the implementation process, allowing evaluation of the efforts
involved in setting up a CI service. In Section 3.4.2, the possibility of
gathering informal user feedback is introduced to comprehend the impact of
the CI service. Section 3.4.3 outlines the design of a questionnaire to be
administered after the final implementation of the CI service, aiming to collect
both qualitative and quantifiable data to provide feedback on the CI service.
Finally, in Section 3.4.4, our plan to utilize quantifiable data obtained from the
automation server is presented to evaluate the effectiveness of the implemented
CI techniques.
The questionnaire is split into three parts. Part A focuses on the general
thoughts of the developers on CI. Part B targets their perception of the
implemented CI service. Part C lets the developers evaluate the CI service
according to the 6 guidelines that were proposed by Ståhl and Bosch [32].
As suggested in Saris and Gallhofer’s [44] book about designing ques-
tionnaires for survey research, an introduction to a set of survey questions
was given. This helps to clarify what the subject is supposed to focus on
when answering the question. The complete questionnaire can be found in
Appendix A.
The survey was conducted using a Google Forms∗ questionnaire. The
questionnaire allowed participants to provide their responses and make revi-
sions within a 48-hour timeframe. Each of the three developers (subjects)
completed the questionnaire individually. To ensure privacy, the results
were reported in an anonymized manner, respecting the confidentiality of the
subjects.
3.4.4 CI Metrics
Qualitative data can be used to support the analysis of qualitative data. There
are two sources for quantifiable data in the CI service: the SCM tool and the
automation server.
∗
https://www.google.com/forms/about/ (Accessed at 22/05/2023)
Methodology | 33
No. Question
Part A
QA.1 What does CI mean to you?
QA.2 In what way does CI change the way of developing?
QA.3 What experiences do you have developing without a CI Service in place?
QA.4 What kind of improvements do you expect from using CI?
QA.5 What downsides do you see in using CI?
Part B
QB.1 In what way did you already use the implemented CI service?
QB.2 What impact does the implemented CI service have on your work?
QB.3 What other feature do you desire to be implemented into the CI Service?
QB.4 Do you have any other feedback on the CI service prototype?
Part C
QC.1 Comprehensive Activities: Are the artefacts produced by the CI service
of value to you (i.e. unit test results)?
QC.2 Effective Communication: Is the output of the CI service easy to access
and understand?
QC.3 Immediacy: Is the CI service output available quickly enough?
QC.4 Appropriate Dimensioning: Does the CI service have a good balance
between completeness and lucidity of the output? In other words: Is a
reasonable amount of activities implemented?
QC.5 Accuracy: Are you confident that the CI service always processes the
recent source code and not an old version?
QC.6 Lucidity: Do you understand all activities included in the CI service and
the chronological order of their execution?
SCM Data. The SCM tool is responsible for managing various metrics
related to the version control system. It keeps track of metrics such as the
number of commits made per branch, per developer, and per specific time
period. Additionally, it provides detailed information about each commit,
including the number of files and lines of code that have been changed, added,
or deleted. This data provides valuable insights into the development activity
and the effects of code changes on the codebase over time. Consequently, it can
be utilised to assess the impact of a CI service on the development process.
However, in the case of Cobolt, we lack a comprehensive understanding of
their development practices, which would be necessary to accurately interpret
this data from before the adoption of the CI service. Therefore, this particular
method cannot be employed to explore the influence of the CI service on the
34 | Methodology
Key Description
id Unique identifier for the stage.
name Stage name, that was specified in the stage definition.
execNode Name of the executing node.
status Denotes the execution status of a stage. It can have
one of the following values: [S:SUCCESS, F:FAILED,
A:ABORTED, U:UNSTABLE, NE:NOT_EXECUTED,
IP:IN_PROGRESS, PPI:PAUSED_PENDING_INPUT,
PPA:PAUSED_PENDING_APPROVAL,
U:UNKNOWN].
startTimeMillis Timestamp indicating the start time of the stage execution
in milliseconds.
durationMillis Duration of the stage execution in milliseconds.
pauseDurationMillis Duration of any pauses or delays encountered during the
stage execution in milliseconds.
error Error message or details, if any, associated with the stage
execution.
We employ a Python script that counts the occurrence of each status for
every pipeline stage.
3.6 Summary
This chapter presents the research methodology for our study on CI for
modular firmware architectures in the embedded systems domain. The
primary objectives of the study include identifying suitable CI techniques,
understanding the efforts and challenges involved in building a CI infras-
tructure and exploring the benefits of implementing such an infrastructure.
The research focuses on implementing and analyzing a CI service prototype
at Cobolt, a company in the embedded systems domain. The emphasis is
on studying the implementation efforts and examining the impact of the CI
service on the development process. The research follows an agile approach,
divided into four iterative stages. Each stage results in a deployable CI
service increment, enabling continuous stakeholder feedback and parallel data
collection. To gather data for the study, a combination of qualitative data
from the researcher’s experience and user feedback, along with quantitative
data from CI metrics, is collected and analyzed. An interpretive research
paradigm is employed in this study, involving the interpretation of qualitative
data within the specific context of Cobolt. This approach allows for a
deeper understanding of the implications and outcomes of implementing
CI techniques in the company. The chapter also discusses the hardware
requirements for implementing the CI service.
Implementation | 37
Chapter 4
Implementation
Checkout Generate
Build Alpaca
SCM: Lysa Build System
Build Bobcat
Build
Capybara
prevent displaying the pipeline correctly in the BlueOcean user interface [45].
We decided to instead execute only the build system generation and unit testing
in parallel as shown in Figure 4.2 and thus are still able to visualise the pipeline
entirely.
Checkout Generate
Build Alpaca
SCM: Lysa Build System
Build
Capybara
Figure 4.2: Parallel execution of the unit testing and build system generation
stage
The unit testing framework is executed on the build machine itself and thus
must be compiled with a C/C++ compiler for x86/x64 architectures.
After adding the unit testing pipeline stage, it did not work right away. It
appeared, that the script that generates the parameters for the unit test suite
generator cxxtestgen is dynamic and dependent on the project location. The
long Jenkins path for the workspace (C:/Jenkins/workspace/Lysa) resulted in
exceeding the Windows command-line string limitation boundary of 8191
chars [46]. The analysis and resolution of this issue took one day. The
final solution was to rewrite the script to generate parameters that use relative
instead of absolute paths, to make the script execution independent from the
source code location.
Finally, we had to decide how the unit test results should be displayed.
The Jenkins handbook [27] suggests that there are plugins for displaying any
widely-used test report format. Since CxxTest can output test results in an
XML format that conforms to the XML standard used by other xUnit tools, we
selected the common JUnit plugin [47] to display the unit test results. Using
the BlueOcean UX plugin. When test cases fail, the Jenkins build is marked
as UNSTABLE. However, when the test suite compilation fails, the Jenkins
build is marked as FAILED.
2. Store credentials for the Bitbucket SCM server to get access to the source
code.
3. Copy previously described pipeline job, its build trigger, and SCM
repository connection.
In just one week the CI service detected two feature integrations that broke
the unit testing stage. The respective developers did not know until they
were manually notified. Each time the issue was resolved after less than 1h.
Since this is only a CI service prototype, we opted against implementing email
notifications for unsuccessful builds. This choice aims to avoid any potential
Implementation | 41
intrusion. Our preference was to encourage developers to engage with the self-
sufficient web frontend for updates instead.
Checkout Generate
Build Alpaca
SCM: Lysa Build System
Build
Capybara
Figure 4.3 shows only the download of Bobcat. Due to limited hardware
availability, we decided to only use a 06-01 DPL laser for this test setup and
integrate the other Lysa hardware targets later.
Usually, Cobolt developers download firmware to test hardware using the
IAR Embedded Workbench IDE. However, in a CI setup, this needs to be
done using a command line program instead. For this, we used the command
line tool J-Link Commander, which is used in version 6.00h by the IAR
Embedded Workbench IDE. The biggest challenge was thereby, that the J-
Link Commander, does not allow to specify the firmware image as a program
parameter and instead requires to select the file in a command line dialogue.
Luckily, there is the option to automate tasks using the J-Link script language
[48]. The workaround was thus, to dynamically create a J-Link Command File
in the Jenkins pipeline that would then be given as an argument to the J-Link
Commander.
After initially implementing the downloading stage, we discovered that the
new firmware was not booting correctly. It became clear that the Ninja build
system that was generated by CMake did not compile an identical firmware
image to the one compiled by the IAR Embedded Workbench IDE. It was not
clear why the images differed, but a workaround was found after 3 days. The
IAR Embedded Workbench IDE uses the command line tool iarbuild to build
IAR project targets. After changing the Jenkins pipeline to use the iarbuild
42 | Implementation
Checkout Generate
Build Alpaca
SCM: Lysa Build System
Notice, that there are two new, additional stages. Apart from the actual
system test stage, there is also a stage for unit testing the LATE test program
with the program pytest, which is executed in parallel to the Lysa unit testing
stage. Pytest offers printing test results in xUnit XML format and thus can
easily be parsed to the general test viewer using the Jenkins JUnit plugin [46]
The LATE testing framework included a large number of tests, that
required manual user input, to the command line and the laser hardware. Those
tests were excluded from the initial CI service implementation, as they would
require designing a hardware-in-the-loop simulation (HILS) setup to simulate
the input. Since LATE is a rather new software product at Cobolt, it is not so
feature-rich and we had to implement a parser for xUnit XML output first.
CI Controller installed on
Webinterface
(Jenkins)
installed on installed on
Principal Server
monitors for
code changes CI Controller
SCM (Jenkins)
monitors for (Bitbucket)
CI feedback
Developer
installed on
Compiler toolchain
can manipulate
and build tools
connected
installed on installed on
connected to to
Each developer works on their personal workstation as they did before the
CI service implementation. The workstation has all the necessary tooling
installed and is connected to laser hardware, so the developer can test and
debug their code. A developer usually works on code changes that are specific
to one specific laser, that the code is tested on.
When a feature or a bug fix is ready, it is pushed to the SCM system and
code changes are merged. Jenkins is installed on the same server as the SCM
system and monitors it for code changes. When new code is available, it
triggers a pipeline execution on an external build server, that has the same
tooling installed as the workstations of the developers. The build server is
supposed to test on all available hardware targets, that are compiled from the
Lysa firmware project. However, for this prototype only one Cobolt 06-01 DPL
laser [25] is connected, thus only one firmware is tested with the system testing
framework LATE. More build machines can be integrated easily to scale up
the number of test runners.
44 | Implementation
The results of the pipeline execution are reported back from the Jenkins
Agent to the Jenkins controller on the principal server and displayed in a web
interface. Developers monitor the web interface to receive feedback on the
pipeline execution. When tests or stages of the pipeline fail, they are supposed
to react instantly by hot-fixing the issue.
After completing the setup of the CI service and infrastructure deployment,
the next step was to discuss its usage with the Cobolt developers. In their work,
Ståhl et al. [32] propose an integration flow model that effectively visualises
CI processes. Figure 4.6 shows the model that was presented to the Cobolt
developers.
manual
triggers
4.8 Summary
This chapter details the step-by-step CI service implementation and addresses
challenges with proactive solutions.
We established a local Jenkins server for initial testing and created a
Freestyle job for compiling Lysa firmware Capybara, before introducing a
declarative pipeline for parallel firmware compilation. Three distinct firmware
targets were built independently, sharing common initialization steps.
We added a unit testing stage using CxxTest. The build system generation
and unit testing were executed concurrently. The script for generating the
unit testing suite faced issues with long file paths, necessitating rewriting for
relative paths. The JUnit plugin displayed unit test results in Jenkins’ web
view, marking builds as successful, unstable, or failed based on tests.
We addressed deploying the CI service next, proposing a distributed
architecture with a principal server as a controller and external build nodes
for scalability. The principal server was Docker-installed, while the physically
accessible build machine facilitated hardware installation and administration.
Then, we added a download stage to the automation pipeline, utilizing J-
Link Commander CLI for the firmware download. Challenges arose spec-
ifying the firmware image as a program parameter, requiring J-Link script
language.
We introduced a system testing stage using Cobolt’s LATE framework.
The pipeline included parallel unit testing of the LATE framework alongside
the unit testing of Lysa. Parsing xUnit XML from LATE testing required the
implementation of a custom parser.
The chapter concludes with CI service infrastructure setup. Developers
continued working on workstations, linked to laser hardware. Pushing code to
the Git repository triggered the CI service to build and test, offering feedback
on status and results.
46 | Implementation
Results and Analysis | 47
Chapter 5
In the subsequent sections, we present the findings obtained from our study. To
begin with, Section 5.1 analyses the results derived from the implementation
notebook, which is summarised in Chapter 4. Then, Section 5.2 reflects on
the informal user feedback that was gathered throughout the study. Moving
on, Section 5.3 presents and summarizes the knowledge acquired from the
final survey, offering additional perspectives on the perceived impact of
the implemented CI service. This section includes an overview of the
survey results and the insights they provide. Lastly, Section 5.4 presents
the quantifiable data collected using the Jenkins API. We explain the nec-
essary preparations undertaken to analyse the data according to the methods
described in Section 3.5.
6. System testing poses challenge es, particularly when certain tests require
manual user input, which cannot be automated without a HILS system.
5.3 Survey
The survey was sent out on Monday, 2023-05-23 at 11:30 to the three
developers at Cobolt. All replies were received within 24 hours. In this
50 | Results and Analysis
QA.1: What does CI mean to you? All three respondents answered that
CI means automated testing to them. D2 mentioned “safeguarding the main
branch” from introducing bugs as a purpose of the automated testing. D3
thinks that fast development and delivering cycles is a motivation for using
CI.
QA.2: In what way does CI change the way of developing? CI impacts the
way of developing by removing test effort from developers (D1, D2, D3). In
software projects with multiple compilation targets, this is wanted because of
the higher regression testing effort (D3). According to D3, Lysa’s modular
firmware architecture shares 90-95% of the source code between multiple
targets, which means that code changes most likely affect all of them. D1
mentions that the usage of CI for testing removes the “works on my machine”
factor, as the build machine represents a non-changing build environment,
unlike the developers’ workstations. All three developers agree, that CI helps
to improve the confidence that checked-in code is correct, which D3 sees as
a key enabler for more frequent releasing. Ultimately, D3 finds it pleasant
that CI allows automating processes with many manual steps (i.e. the release
process that consists of 15 manual steps at Cobolt).
QA.5: What downsides do you see in using CI? The downsides of CI are
linked to the initial effort that goes into the setup (D1) and its maintenance
overhead (D2, D3). D3 sees it as an issue, that somebody needs to be
responsible for the CI and D1 argues, that the CI server might get overloaded
which results in unnecessary wait time.
QB.1: In what way did you already use the implemented CI service? In
the scope of this thesis, D1 was only assigned to projects that were not using
the Lysa project and thus didn’t use CI service so far. The other two developers
used the pipeline view of the job execution to verify their code integrations.
D3 looked closer into the CI activities to plan the release process automation.
QB.2: What impact does the implemented CI service have on your work?
Despite not having used the CI service so far, D1 assumes that when they need
to work with Project Lysa again, it can be considered that the main branch is
in a stable state. D3 comes to the same conclusion and has already used the
CI service. D2 and D3 report that they are more motivated. D2 argues that
implemented CI makes the work-life “less cumbersome” which we believe
is due to the automation of otherwise manual tasks. Using CI apparently
eliminates the uncertainty of making mistakes (D3). We assume that D3
talks about mistakes that happen when validating code changes during their
integration. Overall the implemented CI gives confidence in Project Lysa’s
code quality (D3).
Comprehensive Activities D1
6 D2
5 D3
Average
4
Lucidity 3 Effective Communication
Accuracy Immediacy
Appropriate Dimensioning
id name
0 1 2
6 Declarative: Checkout SCM
13 Unit testing Pre Firmware Build Declarative: Post Actions
17 CMake: Generate Build System
18 CMake: Generate Build System
19 Unit testing
21 CMake: Generate Build System / IAR Projects Pre System Testing
22 Build Firmware Targets
23 Unit Testing Build Firmware Targets Build Test Suite
25 CMake: Generate Build System / IAR Projects
27 Clone LATE framework
29 Build Test Suite
30 Clone LATE framework Alpaca
31 Alpaca
32 Build Test Suite Bobcat
33 Bobcat
34 Execute Test Suite Capybara
35 Capybara
38 Execute Late unit tests
40 Execute Test Suite
46 Build Firmware Targets
47 Execute Late unit tests
48 Declarative: Post Actions
49 Declarative: Post Actions
50 Execute Test Suite
51 Declarative: Post Actions
54 Alpaca
55 Build Firmware Targets
56 Bobcat
54 | Results and Analysis
From Table 5.1, it can be observed, that some stage ids are allocated
with 2 and sometimes even 3 stages. Our first guess was, that this reflects
a changing name of one specific stage. However, we never changed the
stage with the name “Alpaca” throughout the whole implementation process.
Yet, the allocated name for id 30 changed from “Alpaca” to “Clone LATE
framework”. A more plausible explanation is, that when changing the pipeline
architecture, some stages get a new identifier, which allows reallocating the
now obsolete ones, even though they have been used before.
Unfortunately, we did not know about this prior to the implementation
process. Otherwise, we would have given every stage unique consistent
names so we could later sort the data with them. Now some stages such as
“upload” (later renamed to “download”) were used to describe both the stage
of downloading the Bobcat as well as the Capybara firmware. Yet, most stages
have unique names and can be further processed.
Results and Analysis | 55
Data Slicing
To capture different iteration states of the CI service, we divided the dataset
into meaningful slices, each representing a subset of pipeline executions.
These slices were carefully selected to ensure they reflect specific iteration
levels of the implementation process. Importantly, there are no duplicate
allocations of any id across these slices. The table below, Table 5.2, provides
an overview of the slicing, along with a description for each slice.
Table 5.3: Status of all stages in Slice 2 (S: SUCCESS; F: FAILED; NE:
NOT_EXECUTED)
occurs before the stages “Alpaca,” “Bobcat,” and “Capybara” responsible for
compiling different firmware targets, as well as the “Declarative: Post Actions”
stage used for parsing unit test results to the JUnit plugin, these downstream
stages receive alternate stage ids. We excluded those ids from further analysis,
as they do not represent properly executed stages.
Table 5.4: Status of all stages in Slice 3 (The stage names “build” and
“upload” were manually appended with a descriptor; S: SUCCESS; NE:
NOT_EXECUTED)
nr name id status
S F NE NaN
1 Declarative: Checkout SCM 6 24 0 0 0
2 Unit testing 13 14 10 0 0
3 CMake: Generate Build System 18 24 0 0 0
4 Alpaca 31 0 0 14 10
5 Bobcat 33 13 1 0 10
6 Capybara 35 14 0 0 10
7 Declarative: Post Actions 51 14 0 0 10
This was fixed with pipeline execution 78. This architectural modification
of the pipeline resulted in the downloading stages being assigned to multiple
stage ids. We merged their results.
Table 5.6: Status count for each stage of Slice 3 (The stage names “build”
and “upload” were manually appended with a descriptor; S: SUCCESS; F:
FAILED; NE: NOT_EXECUTED; NaN: No value)
nr name id status
S F NE NaN
1 Declarative: Checkout SCM 6 3 0 0 0
2 CMake: Generate Build Sys- 21 3 0 0 0
tem / IAR Projects
3 Build Test Suite 23 3 0 0 0
4 Execute Test Suite 34 3 0 0 0
5 Alpaca 54 0 0 3 0
6 build [Bobcat] 63 3 0 0 0
7 build [Capybara] 65 3 0 0 0
8 upload [Capybara] 71, 73, 76 1 0 2 0
9 upload [Bobcat] 75, 80 2 0 0 1
Table 5.7: Status count for each stage of Slice 5 (S: SUCCESS; F: FAILED;
U: UNSTABLE; NE: NOT_EXECUTED; A: ABORTED; NaN: No value)
nr name id status
S F U NE A NaN
1 Declarative: Checkout SCM 6 35 1 0 0 5 0
2 CMake: Generate Build Sys- 25 34 0 0 1 0 6
tem / IAR Projects
3 Clone LATE framework 27 34 0 0 0 0 7
4 Build Test Suite 29 34 0 0 0 0 7
5 Execute Late unit tests 47 34 0 0 0 0 7
6 Execute Test Suite 58 31 3 0 0 0 7
7 Alpaca 78 0 3 0 31 0 7
8 download [Bobcat] 83, 95, 96, 27 7 0 0 1 6
98, 100
9 build [Bobcat] 87 27 7 0 0 0 7
10 build [Capybara] 89 29 5 0 0 0 7
11 test [Bobcat] 105 2 2 23 0 0 14
efforts, the exact cause of this issue could not be determined and it was decided
to restart the build machine. This caused a failed status in execution 110 but
apparently solved the issue and the stage started functioning correctly again in
execution 111.
The unit test execution stage “Execute Test Suite” failed 3 times due to
faulty code changes in execution 111, 112 and 116. Unlike in most of the
other cases that did not result in a changing stage id for most downstream
stages. Thus, the stages “Alpaca”, “build [Bobcat]”, “build [Capybara]” and
“download [Bobcat]” report 3 extra failing states, even when they were actually
skipped.
In execution 96, it occurred that the build stage for Bobcat failed, while
the Capybara firmware was still building correctly. This was resolved by the
respective developer in two iterations. In execution 118 and 119, both Bobcat
and Capybara could not be built. This was resolved at execution 120. The four
failures of “build [Bobcat]” resulted in 4 failure reports for stage “download
[Bobcat]” when it actually was skipped.
104
duration [ms]
103
102
1 2 3 4 5 6 7
stage nr
Figure 5.2: Logarithmic box plot for each stage duration of Slice 2
The unit testing stage (nr 13) takes the longest with 42401 ± 1912 ms.
The second longest takes the building of the firmware. Bobcat takes 31425 ±
7231ms and Capybara 31693±5294ms. The large standard deviation for those
firmware build stages comes from one outlier stemming from the pipeline
execution 73. The build of Bobcat failed after 8135 ms and Capybara builds in
just 16426 ms. Both firmware targets are built in parallel and we assume, that
because of the fast failure of the Bobcat build, more hardware resources were
distributed to the Capybara build executer.
The firmware target Alpaca was marked to be skipped in the pipeline
description file and its execution time is measured to be 189 ± 59 ms.
105
104
duration [ms]
103
1 2 3 4 5 6 7 8 9
stage nr
Figure 5.3: Logarithmic box plot for each stage duration of Slice 3
values differ quite a lot. While this stage takes 3584 ± 2354 ms in Slice 3, it
takes 10875 ± 5858 ms in Slice 3.
In execution 77, stage id 6 took 2875 ms, while in execution 78, it took
16741 ms. The command line logs of Jenkins revealed that in execution 78,
64 | Results and Analysis
the git repository had to be initialised instead of just being synchronised with
the SCM. It is assumed that the workspace folder was manually deleted before
execution 78.
To verify this assumption, we manually deleted the workspace and trig-
gered a new pipeline execution. Jenkins reported an execution time of
19533 ms, supporting our conclusion that deleting the workspace led to the
need for git repository initialization.
Another noticeable observation is the increased duration for the build
system generation and firmware building stages from Slice 2 to Slice 3. The
build system generation now takes an average of 6112 ± 1286 ms. The build
of Bobcat takes an average of 78787 ± 1554 ms, and Capybara requires an
average of 78756 ± 1554 ms to build. We attribute this increase to the switch
from using the faster Ninja build tool to the slower IAR build tool.
The stage “upload [Capybara]” has only one valid record point (18567 ms)
from execution 77, before being skipped in the other two executions of Slice
3. Downloading the firmware to the Bobcat target takes 18617 ± 25 ms.
The unit testing, which was split up into a build and an execution phase
takes 46206 ± 758 ms for the building and 1014 ± 245ms which is slightly
higher than what was reported for Slice 2. We attribute this increase to the
additional step introduced in execution 77, where the build folder is always
deleted before the building process begins. This extra step adds some overhead
to the overall execution time.
108
107
106
duration [ms]
105
104
103
102
1 2 3 4 5 6 7 8 9 10 11
stage nr
Figure 5.4: Logarithmic box plot for each stage duration of Slice 5
The remaining six outliers occurred between execution 105 and 110. As
previously discussed in Section 5.4.2, these outliers correspond to instances
where the checkout stage became stuck and had to be manually aborted.
The stage for generating the build system with CMake is slightly lower in
duration with an average of 4927 ± 1085 ms compared to Slice 3, but it falls
within a similar range. However, we would have expected a slight increase
in duration due to the extra stages for cloning (id 27) and unit testing of the
LATE framework that are executed in parallel to the Lysa unit testing and the
build system generation. Especially because this behaviour is noticeable in the
Lysa unit testing stages. The stage “Build Test Suite” takes 51645 ± 5554 ms
and stage “Execute Test Suite” requires 2006 ± 6641 ms. The relatively large
standard deviation for the latter can be explained by the existence of two large
outliers reported in execution 111 (39562 ms) and 112 (2781 ms), which were
caused by an error in the unit test suite execution due to a faulty code change.
The cloning of the late framework always initialises its git repository as
the respective folder gets deleted before checking out the source code. This
explains the relatively long duration of 23252 ± 1411 ms. The unit tests of
LATE take an average of 2006 ± 1177 ms. While the duration of the cloning
66 | Results and Analysis
marked the median values of the critical path in bold in Table 5.10 and summed
them to get the median value for the duration of the critical path which is
158287ms or approximately 2min38s.
5.5 Summary
We presented the findings from our experimental single-case study. We first
discuss the learned lessons from the implementation process, such as the initial
effort to learn Jenkins, its suitability for iterative development, challenges
due to proprietary components, and the benefits of using distributed build
infrastructures.
User feedback revealed positive interest initially due to Jenkins’ intuitive
interface, yet developers lacked preparation, leading to code changes without
subsequent CI checks. Over time, user confidence grew, though concerns
arose about passing system tests and testing framework effectiveness.
A survey among developers highlighted CI’s association with automated
testing, reducing test efforts, and improving code quality. Expectations
included faster bug feedback, task automation, and better time utilization.
Initial setup and maintenance, along with potential CI server overload, were
noted as downsides.
The survey also gauged the impact of the implemented CI service on
Cobolt’s development, showing increased code quality confidence and mo-
tivation. Quantitative evaluation endorsed the CI service.
Metrics from the CI server, especially pipeline executions and stages,
were analyzed. Consistent stage identifiers were stressed for comprehensive
analysis. Findings supported the success of CI techniques like automated unit
testing and multi-target compilation.
68 | Results and Analysis
Discussion | 69
Chapter 6
Discussion
6.1 CI Techniques
We identified 8 CI techniques throughout our experimental study and per-
formed an iterative CI implementation using Jenkins. The service incorporates
multi-target compilation, automated unit testing, test reporting, visual CI
feedback, and trunk-based development. These techniques prove effective
for embedded software with a modular firmware architecture. However,
automated system testing encounters limitations due to the need for manual
interaction with hardware targets. In this section, we discuss each of the
identified techniques.
culties for later analysis of CI metrics, as it hinders the clear tracking of stage
behaviours over time.
This iterative implementation approach offers the advantage of faster
availability of CI activities. Even after the initial deployment, which included
only the multi-target compilation and unit testing stage, we were able to
identify specific bugs, as mentioned in Section 5.4.2.
Based on our experiences with implementing CI service iteratively, we
conclude it to be a valuable technique for CI in the embedded domain.
ously described in Section 6.1.5, we can use a build machine, that is identical
to developer workstations when utilising a distributed build architecture.
Chapter 7
In this final chapter we present our conclusions (Section 7.1), present our
limitation (Section 7.2), discuss future work (Section 7.3), and elaborate on
our reflection (Section 7.4).
7.1 Conclusions
CI is a software development activity that supports the synchronisation of
multiple developers coding activities. The idea is to encourage developers to
commit their code changes faster by having a service in place, that automati-
cally validates the correctness of the code changes. While CI is widely adopted
in web and application development, there is a lack of solution proposals
for applying it to the embedded domain. Embedded software — also called
firmware — is software that runs on hardware that is embedded in a specific
context. The hardware and firmware are often developed concurrently and the
product needs to comply with special working conditions. Embedded software
development is often cross-compiled on an external workstation. The firmware
must then be downloaded to the memory of the hardware target as a binary file.
In this thesis, we investigated the application of CI techniques in the
context of embedded software development. Our study identifies suitable
CI techniques for the embedded domain, assesses the implementation efforts
involved, and evaluates the impact of CI adoption.
Through an iterative development and deployment process, we success-
fully implemented a CI service using the automation server Jenkins at Cobolt
AB, a company specializing in optoelectronics. The CI service incorporated
iterative CI implementation, multi-target compilation, automated unit testing,
test reporting in xUnit XML format, visual CI feedback, and trunk-based
78 | Conclusions and Future work
7.2 Limitations
The Cobolts lasers are not readily available in large quantities to the de-
velopment team. Consequently, the team must prioritize the distribution
of hardware resources. Due to this limitation, we were constrained to
downloading and system-testing the firmware exclusively on the DPL version
of the 06-01 series laser. We focused on developing an extendable CI service,
that we believes allows easy integration of additional hardware targets at a later
stage. However, it is important to note that our thesis work does not encompass
the challenges that may arise from the parallel usage of multiple debuggers and
hardware targets.
Part B of the questionnaire gauges the developers’ perception of the
implemented CI service. However, due to the ongoing research on the
implemented CI techniques, we refrained from seeking concrete feedback
on them. Instead, we requested general feedback, which restricted our
understanding of the developers’ perception of specific CI techniques.
7.4 Reflections
The purpose of our research, as outlined in Section 1.3, is to contribute to the
United Nations’ sustainable development goal 9, “Promoting Technological
80 | Conclusions and Future work
References
com/blog/unit-testing-for-embedded-software-development/ (Accessed
at 11/04/2023).
[28] IAR Systems AB, IAR IDE Project Management and Building Guide
(UIDEARM-9), 2015, this guide applies to version 7.4x of IAR
Embedded Workbench® for Advanced RISC Machines Ltd’s ARM core
family.
[42] Jenkins, “Architecting for scale,” May 2023. [Online]. Available: https:
//www.jenkins.io/doc/book/scaling/architecting-for-scale/ (Accessed at
02/05/2023).
[48] S. M. G. . C. KG, J-Link / J-Trace User Guide (V6.00), Jun 2016, this
guide applies to version 7.70.x of IAR Embedded Workbench® for AR.
88 | REFERENCES
Appendix A: Questionnaire | 89
Appendix A
Questionnaire
Following are the screenshots displaying the questionnaire we’ve put together
using the Google Forms platform.
Questionnaire: Continuous Integration for Firmware
Development Division at Cobolt
As part of the master thesis
"Continuous Integration for Embedded Software with Modular Firmware Architecture" we want to understand:
1. Which Continuous Integration (CI) techniques are suitable for embedded software with
modular firmware architecture?
2. What are the benefits from using a CI service in the embedded domain?
Please enter your email, so you have the possibility to revise your answers.
All data will be presented anonymized in the thesis report.
1. Email *
PART A: General
An early definition of Continuous Integration (CI) was provided by Beck in his 1999’s article about extreme programming:
"New code is integrated with the current system after no more than a few hours. When integrating, the system is built from scratch
and all tests must pass or the changes are discarded."
In more recent definitions of CI, especially in the context of DevOps, it is further specified that there must be an automated system.
When an agent checks in their revised code, this system picks up the change and runs a set of commands to verify the correctness
automatically.
Please answer the following questions based on your current understanding and opinion on CI.
A CI service
prototype was implemented in Cobolt. Its infrastructure can be viewed in Figure 1. Figure 2 shows
the CI pipeline that is initiated on the CI Agent by the CI Controller. This
part of the questionnaire is targeted on getting your feedback regarding the
implementation.
Ståhl and Bosch (Link) have proposed 6 guidelines for the implementation of CI services, that are used to evaluate the CI service that
was implemented at Cobolt.
Please rate the following criteria on a scale from 0 to 6. if you want to discuss what any of the categories mean, please get in touch
with me.
11. Comprehensive Activities *
Are the artefacts produced by the CI service of value to you (i. e. unit test results)?
not at all
very much
not at all
very much
13. Immediacy *
Is the CI service output available quick enough?
not at all
very much
not at all
very much
15. Accuracy *
Are you confident that the CI service always processes the recent source code and not an old version?
not at all
very much
16. Lucidity *
Do you understand all activities included in the CI service and the chronological order of their execution?
not at all
very much
Forms
96 | Appendix B: Questionnaire Results
Appendix B
Questionnaire Results
Respondant/Question D1 D2 D3 Summary
What does CI mean to you? Automated tests and building on a server Automatic testing safeguarding the main branch from A relatively fast cycle of developing new code, * Automated testing (D1, D2, D3)
implementing new problems after fixing another merging it with other developers' code, running tests * Safeguarding the main branch (D2)
and delivering a binary ready to be tested by non-dev * Fast development and delivering cycles (D3)
people.
In what way does CI change Automated tests takes away a lot of the effort from Added confidence when checking in code. Otherwise The overhead of verifying that all projects compile (as * Remove testing effort from developers (D1, D2, D3)
the way of developing? testing, which makes it possible to make progress lots of doubt whether one has thought of everything, 90-95% of our code is shared between projects) and * Regression testing for multiple project targets (90-
faster. Building on a server takes a way the "works on and that problems may occur down the road. works after every merge into master is gone. The 95% of Lysa code is shared between multiple
my machine" factor. overhead of doing formal releases for internal testing projects) (D3)
(currently about 15 manual steps) is dramatically * Takes away the "works on my machine" factor (D1)
reduced. This obviously makes the process much * Increases confidence that checked in code is correct
more pleasant and the otherwise inherent reluctance (D1, D2, D3)
to do frequent releases (or replace broken releases) * -> more freqient releases (D3)
is no more. * Pleasant to automate release process (15 manual
steps) (D3)
What experiences do you You have to me more careful Both doubt and problems down the road, as That's how we have been working for 5 years now, so * Being more careful (D1)
have developing without a CI mentioned. This sometimes leads to confusion and or quite a lot. * Small flaws (forgotten safety steps) result in big
Service in place? annoyance. A small thing one forgets or don't think problems (D2)
about when having implemented something, may lead * Confusion for the team, as problems cannot be
to a bigger thing for either the same person after traced to a specific change (D2)
some time or another person.
What kind of improvements Notice quicker if something doesn't work right. More of actual problem solving and improvements, Developers can focus on developing while a lot of * Faster feedback about bugs (D1)
do you expect from using CI? less silly made up problems boring, time consuming and repetitive tasks are no * Better use of time (less problem analysis) (D2, D3)
longer their (or any one else's) responsibility. * Automation of repetitive tasks (D3)
What downsides do you see Initial effort to set it up. Sometimes servers get over Overhead in general. Added moment of inertia if e.g Someone has to be responsible for maintaining the CI * Iniial effort to set up (D1)
in using CI? loaded with work and you have to wait tests get obsolete after changing some requirements environment (but given the positive results I believe * Wait time because of server load (D1)
that's totally worth it). * Maintainance overhead (i.e. requirements change ->
tests needs to be changed) (D2, D3)
* New responsibility (D3)
In what way did you already Haven't used it yet See green/red boxes clearly in web interface in case I As a receipt that what I push to master is actually * One has not used it (assigned to other project) (D1)
use the implemented CI forgot something. Sometime exposed and been working. I also see that there's just little work left * Pipeline view to verify merge (D2, D3)
service? reminded from colleague that something did not pass before most of the release procedure can be * Waits for release process to be automated (D3)
automated.
What impact does the If I would check out master to do work on Lysa, it Makes worklife more exciting and less cumbersome Knowing that the quality of the firmware is being * Main line is always tested (D1, D3)
implemented CI service have would already be tested. continuously verified significantly increases * Increased motivation (D2, D3)
on your work? motivation to fix things fast and release them * Elimitates uncertanty of doing something wrong (D3)
regularly. Before this, releasing felt a bit * Confidence that product is of good quality (D3)
overwhelming, always having this worry that
something fundamental that I fail to detect is going to
be released to the users, leading to their irritation and
lack of confidence in the produced code.
What other feature do you create dfu file (if it isn't already) Release procedure. Also would be nice with more Automated release procedure (this is very close now). * Automate release process (D1, D2, D3)
desire to be implemented into hardware tests, including simulated external user * More hardware tests incl. simulated input (D2)
the CI Service? inputs
Do you have any other Seems good Very grateful for the work done. I clearly see how my * Positive perception (D2, D3)
feedback on the CI service working speed has increased. * Increased working speed (D2)
prototype?
Comprehensive Activities 6 6 6 6
Effective Communication 4 6 6 5,333333333
Immediacy 4 6 5 5
Appropriate Dimensioning 4 6 6 5,333333333
Accuracy 6 6 6 6
Lucidity 5 6 6 5,666666667
TRITA-EECS-EX-2023:847
www.kth.se
For DIVA
{
"Author1": {
"Last name": "Segatz",
"First name": "Fabian",
"Local User Id": "u1sdcy2v",
"E-mail": "segatz@kth.se",
"ORCiD": "0000-0002-1802-0849",
"organisation": {"L1": "School of Electrical Engineering and Computer Science ",
}
},
"Degree": {"Educational program": "Master’s Programme, Embedded Systems, 120 credits"},
"Title": {
"Main title": "Continuous Integration for Embedded Software with Modular Firmware Architecture",
"Language": "eng" },
"Alternative title": {
"Main title": "Kontinuerlig Integration för Inbäddad Programvara med Modulär Firmware-Arkitektur",
"Language": "swe"
},
"Supervisor1": {
"Last name": "Fu",
"First name": "Han",
"Local User Id": "u1d7tcbu",
"E-mail": "hfu@kth.se",
"organisation": {"L1": "School of Electrical Engineering and Computer Science ",
"L2": "CS" }
},
"Supervisor2": {
"Last name": "Elgcrona",
"First name": "Gunnar",
"E-mail": "gunnar.elgcrona@cobolt.se",
"Other organisation": "Cobolt AB"}
},
"Examiner1": {
"Last name": "Artho",
"First name": "Cyrille",
"Local User Id": "u1tesytk",
"E-mail": "artho@kth.se",
"organisation": {"L1": "School of Electrical Engineering and Computer Science ",
"L2": "CS" }
},
"Cooperation": { "Partner_name": "Cobolt AB"},
"Other information": {
"Year": "2023", "Number of pages": "xv,97"}
}