我正在尝试将大型 FPGA 构建移至 Jenkins CI 环境中,但当在 Jenkins 生成的 Docker 容器中运行时,构建会在综合结束时挂起。
我尝试复制 Jenkins 正在创建的环境,但是当我自己生成 Docker 容器时,构建没有问题。
我已经尝试过:
-nolog -nojournal
选项
用于删除任何日志文件冲突的命令我还有一个非常小的构建,可以毫无问题地完成 Jenkins 中的整个构建过程,因此我认为我的 Docker 容器不存在根本缺陷。
agent {
docker {
image "vivado:2017.4"
args """
-v <MOUNT XILINX LICENSE FILE>
--dns <DNS_ADDRESS>
--mac-address <MAC_ADDRESS>
"""
}
}
steps {
sh "chmod -R 777 ."
dir(path: "${params.root_dir}") {
timeout(time: 15, unit: 'MINUTES') {
// Create HLS IP for use in Vivado project
sh './run_hls.sh'
}
timeout(time: 20, unit: 'MINUTES') {
// Create vivado project, add sources, constraints, HLS IP, generated IP
sh 'source source_vivado.sh && vivado -mode batch -source tcl/setup_proj.tcl'
}
timeout(time: 20, unit: 'MINUTES') {
// Create block designs from TCL scripts
sh 'source source_vivado.sh && vivado -mode batch -source tcl/run_bd.tcl'
}
timeout(time: 1, unit: 'HOURS') {
// Synthesize complete project
sh 'source source_vivado.sh && vivado -mode batch -source tcl/run_synth.tcl'
}
}
}
下面的代码块正在运行 1 个作业,超时时间为 12 小时。可以看到Synthesis完成了,8小时后出现超时。
[2019-04-17T00:30:06.131Z] Finished Writing Synthesis Report : Time (s): cpu = 00:01:53 ; elapsed = 00:03:03 . Memory (MB): peak = 3288.852 ; gain = 1750.379 ; free physical = 332 ; free virtual = 28594
[2019-04-17T00:30:06.131Z] ---------------------------------------------------------------------------------
[2019-04-17T00:30:06.131Z] Synthesis finished with 0 errors, 0 critical warnings and 671 warnings.
[2019-04-17T08:38:37.742Z] Sending interrupt signal to process
[2019-04-17T08:38:43.013Z] Terminated
[2019-04-17T08:38:43.013Z]
[2019-04-17T08:38:43.013Z] Session terminated, killing shell... ...killed.
[2019-04-17T08:38:43.013Z] script returned exit code 143
在本地生成的 Docker 容器中运行相同的命令没有任何问题。不幸的是,
timeout
Jenkins 步骤似乎没有刷新打开的缓冲区,因为我打印出所有日志文件的 post:unsuccesful
步骤没有找到 synth_1
,尽管我不希望有任何与詹金斯捕获。
Jenkins/Vivado 集成是否存在任何已知问题?有没有办法进入 Jenkins 生成的容器,以便我可以尝试复制我所期望的与我正在经历的?
编辑:我已经在实际的 tcl 脚本中添加了超时,以超越
wait_on_runs
中使用的 run_synth.tcl
命令,但现在我在实现过程中遇到了相同的挂起行为。
问题在于 vivado 处理(或不处理...)其分叉进程的方式。具体来说,我认为这适用于并行综合。这也许就是为什么你只在某些项目中看到它的原因。在您上面描述的状态下(在“综合完成”后卡住),我注意到 vivado 的几个废弃的僵尸进程。据我了解,这些是已结束的子进程,但父进程在结束之前没有收集状态。使用
strace
进行追踪甚至可以发现 vivado 试图终止这些进程:
restart_syscall(<... resuming interrupted nanosleep ...>) = 0
kill(319, SIG_0) = 0
kill(370, SIG_0) = 0
kill(422, SIG_0) = 0
kill(474, SIG_0) = 0
nanosleep({tv_sec=5, tv_nsec=0}, 0x7f86edcf4dd0) = 0
kill(319, SIG_0) = 0
kill(370, SIG_0) = 0
kill(422, SIG_0) = 0
kill(474, SIG_0) = 0
nanosleep({tv_sec=5, tv_nsec=0}, <detached ...>
但是(众所周知)你无法杀死僵尸,它们已经死了......
通常这些进程会被 init 进程采用并在那里处理。但对于 Docker 中的 Jenkins Pipeline,默认情况下没有 init。管道生成容器并运行
cat
,无需任何输入来保持其活动状态。这样 cat
就变成 pid 1 并获取 vivado 被遗弃的孩子。猫当然不知道如何处理它们并忽略它们(真是悲剧)。
cat,1
|-(sh,16)
|-sh,30 -c ...
| |-sh,31 -c ...
| | `-sleep,5913 3
| `-sh,32 -xe /home/user/.jenkins/workspace...
| `-sh,35 -xe /home/user/.jenkins/workspace...
| `-vivado,36 /opt/Xilinx/Vivado/2019.2/bin/vivado -mode tcl ...
| `-loader,60 /opt/Xilinx/Vivado/2019.2/bin/loader -exec vivado -mode tcl ...
| `-vivado,82 -mode tcl ...
| |-{vivado},84
| |-{vivado},85
| |-{vivado},111
| |-{vivado},118
| `-{vivado},564
|-(vivado,319)
|-(vivado,370)
|-(vivado,422)
`-(vivado,474)
幸运的是,有一种方法可以在 docker 容器中拥有一个 init 进程。通过
--init
参数与 docker run
解决了我的问题。
agent {
docker {
image 'vivado:2019.2'
args '--init'
}
}
这将创建 vivado 似乎依赖的 init 进程,并且构建运行没有问题。
希望这对您有帮助!
干杯!
补充 LeChuck 的答案,当我尝试通过 kubernetes 运行 vivado 2020.1 时,我在某些设计上遇到了同样的问题。就我而言,因为我无法在特定集群上启用 PID 命名空间共享,所以我必须在映像中添加并使用 tini,如本答案中所述:Kubernetes 相当于 `docker run --init`
并简单地将
"/tini", "--"
添加到我的 job.yaml 文件的 command
部分的开头。