20 proc generate_prj_badge {prj_name ver color file {is_hls 0}} {
23 set max_characters 20.0
24 if { [
expr {[string length $prj_name] > $max_characters}] } {
25 set scaling_factor [
expr {$max_characters / [string length $prj_name]}]
26 set font_size [
expr {ceil($scaling_factor * $font_size)}]
31 set ver_text "HLS $ver"
39 set right_color "#4527A0"
41 set right_color "#262626"
45 set ver_font_size 11.0
46 set ver_max_characters 12.0
47 if { [
expr {[string length $ver_text] > $ver_max_characters}] } {
48 set ver_scaling [
expr {$ver_max_characters / [string length $ver_text]}]
49 set ver_font_size [
expr {ceil($ver_scaling * $ver_font_size)}]
52 set svg_content "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
53 <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"250\" height=\"20\">
54 <linearGradient id=\"b\" x2=\"0\" y2=\"100%\">
55 <stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>
56 <stop offset=\"1\" stop-opacity=\".1\"/>
58 <mask id=\"hog_prj_badge\">
59 <rect width=\"250\" height=\"20\" rx=\"10\" fill=\"#fff\"/>
61 <g mask=\"url(#hog_prj_badge)\">
62 <path fill=\"$color\" d=\"M0 0h250v20H0z\"/>
63 <path fill=\"$right_color\" d=\"M160 0h90v20H160z\"/>
64 <path fill=\"$right_color\" d=\"M250,20 a1,1 0 0,0 0,-16\"/>
65 <path fill=\"url(#b)\" d=\"M0 0h250v20H0z\"/>
67 <g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"$font_size\">
68 <text x=\"80\" y=\"14\">$prj_name</text>
70 <g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"$ver_font_size\">
71 <text x=\"205\" y=\"14\">$ver_text</text>
82 error "Failed to write to file: $error_msg"
86 proc generate_res_badge {res res_value color file {is_hls 0}} {
91 set value_text $res_value
94 set value_font_size 11.0
95 set value_max_characters 9.0
96 if { [
expr {[string length $value_text] > $value_max_characters}] } {
97 set value_scaling [
expr {$value_max_characters / [string length $value_text]}]
98 set value_font_size [
expr {ceil($value_scaling * $value_font_size)}]
101 set svg_content "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
102 <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"120\" height=\"20\">
103 <linearGradient id=\"b\" x2=\"0\" y2=\"100%\">
104 <stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>
105 <stop offset=\"1\" stop-opacity=\".1\"/>
107 <mask id=\"hog_res_badge\">
108 <rect width=\"120\" height=\"20\" rx=\"3\" fill=\"#fff\"/>
110 <g mask=\"url(#hog_res_badge)\">
111 <path fill=\"#555\" d=\"M0 0h60v20H0z\"/>
112 <path fill=\"$color\" d=\"M60 0h60v20H60z\"/>
113 <path fill=\"url(#b)\" d=\"M0 0h120v20H0z\"/>
115 <g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"11\">
116 <text x=\"30\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">$res</text>
117 <text x=\"30\" y=\"14\">$res</text>
119 <g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"$value_font_size\">
120 <text x=\"90\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">$value_text</text>
121 <text x=\"90\" y=\"14\">$value_text</text>
127 set fh [open $file w]
128 puts $fh $svg_content
132 error "Failed to write to file: $error_msg"
137 set TclPath [
file dirname [
info script]]/..
138 set repo_path [
file normalize "$TclPath/../.."]
139 source $TclPath/hog.tcl
142 set usage "- CI script that creates GitLab badges with utilisation and timing results for a chosen Hog project.\n\
143 USAGE: $::argv0 <push token> <Gitlab api url> <Gitlab project id> <Gitlab project url> <GitLab Server URL> <Hog project|hls:component> <ext_path>\n\
145 <Hog project> Name of a Vivado project in Top/ — produces Vivado badges from bin/<project>-<ver>/utilization.txt\n\
146 hls:<component> Produces HLS badges for a single HLS component located at bin/*/\[vitis_hls/\]<component>/utilization.txt"
148 if {[
llength $argv] < 7} {
154 set result [
catch {
package require json} JsonFound]
155 if {"$result" != "0"} {
156 Msg CriticalWarning "Cannot find JSON package equal or higher than 1.0.\n $JsonFound\n Exiting"
160 set push_token [
lindex $argv 0]
161 set api_url [
lindex $argv 1]
162 set project_id [
lindex $argv 2]
163 set project_url [
lindex $argv 3]
164 set gitlab_url [
lindex $argv 4]
165 set project [
lindex $argv 5]
166 set ext_path [
lindex $argv 6]
168 set resources [dict create "LUTs" "LUTs" "Registers" "FFs" "Block" "BRAM" "URAM" "URAM" "DSPs" "DSPs"]
176 if {[
string match "hls:*" $project]} {
178 set hls_component [
string range $project 4 end]
181 if {!$is_hls_badge} {
186 set current_badges [dict create]
189 Msg Info "Retrieving current badges..."
191 lassign [
ExecuteRet {*}$curl_cmd --header "PRIVATE-TOKEN: $push_token" "$api_url/projects/${project_id}/badges?page=$page" --request GET] ret content
192 set content_dict [json::json2dict $content]
193 if {[
llength $content_dict] > 0} {
194 foreach it $content_dict {
206 proc extract_ver_from_dir {dir_name} {
209 if {[regexp -- {-(v[0-9]+\.[0-9]+\.[0-9]+)(?:-[0-9a-fA-F]+)?$} $dir_name -> v]} {
220 set hls_matches [
concat \
221 [glob -nocomplain $repo_path/bin/*/vitis_hls/$hls_component/utilization.txt] \
222 [glob -nocomplain $repo_path/bin/*/$hls_component/utilization.txt]]
223 if {[
llength $hls_matches] == 0} {
224 Msg CriticalWarning "Cannot find HLS component '$hls_component' binaries in artifacts"
229 if {[
llength $hls_matches] > 1} {
230 Msg Warning "Multiple bin dirs contain HLS component '$hls_component'; using [
lindex $hls_matches 0]"
232 set prj_dir [
file dirname [
lindex $hls_matches 0]]
235 if {[
file tail [
file dirname $parent]] eq "vitis_hls"} {
236 set parent [
file dirname [
file dirname $parent]]
238 set parent [
file dirname $parent]
241 if {$ver eq ""} {
set ver "unknown"}
246 set prj_matches [glob -nocomplain -types d \
247 $repo_path/bin/$project-${ver} \
248 $repo_path/bin/$project-${ver}-*]
249 if {[
llength $prj_matches] == 0} {
250 Msg CriticalWarning "Cannot find $project binaries in artifacts"
254 set prj_dir [
lindex $prj_matches 0]
255 foreach m $prj_matches {
256 if {[
file tail $m] eq "$project-${ver}"} {
set prj_dir $m break}
263 proc parse_vivado_util {lines resources} {
264 set usage_dict [dict create]
265 foreach line $lines {
266 set str [
string map {| ""} $line]
267 set str [
string map {"<" ""} $str]
268 set str [
string trim $str]
269 set usage [
lindex [
split $str] end]
270 foreach res [dict keys $resources] {
271 if {[
string first $res $str] > -1} {
272 set res_name [dict get $resources $res]
273 dict set usage_dict $res_name $usage
283 proc parse_hls_util {lines} {
284 set usage_dict [dict create]
285 set hls_res_map [dict create LUT "LUTs" FF "FFs" BRAM "BRAM" BRAM_18K "BRAM" URAM "URAM" DSP "DSPs"]
286 foreach line $lines {
287 if {![regexp -- {^\s*\|\s*([A-Za-z_0-9]+)\s*\|\s*\S+\s*\|\s*\S+\s*\|\s*(\S+)\s*\|} $line -> site pct]} {
290 if {[dict exists $hls_res_map $site]} {
291 set res_name [dict get $hls_res_map $site]
292 if {[
string is double -strict $pct]} {
293 dict set usage_dict $res_name $pct
298 set ordered [dict create]
299 foreach res_name {LUTs FFs BRAM URAM DSPs} {
300 if {[dict exists $usage_dict $res_name]} {
301 dict set ordered $res_name [dict get $usage_dict $res_name]
317 proc emit_badges {util_dir badge_suffix label_left is_hls util_dict ver new_badges_var} {
318 upvar 1 $new_badges_var new_badges
321 if {[
file exists $util_dir/timing_error.txt]} {
323 }
elseif {[
file exists $util_dir/timing_ok.txt]} {
328 dict set new_badges "timing-$badge_suffix" "timing-$badge_suffix"
331 foreach res [dict keys $util_dict] {
332 set usage [
DictGet $util_dict $res]
333 set res_value "$usage\% "
334 if {[
expr {$usage < 50.0}]} {
336 }
elseif {[
expr {$usage < 80.0}]} {
341 dict set new_badges "$res-$badge_suffix" "$res-$badge_suffix"
347 set new_badges [dict create]
354 set fp [open utilization.txt]
355 set hls_lines [
split [read $fp] "\n"]
358 emit_badges "." $hls_component $hls_component 1 $hls_util_dict $ver new_badges
363 set prj_name [
string map {/ _} $project]
364 if {[
file exists utilization.txt]} {
365 set fp [open utilization.txt]
366 set vivado_lines [
split [read $fp] "\n"]
369 emit_badges "." $prj_name $prj_name 0 $vivado_util $ver new_badges
374 foreach badge_name [dict keys $new_badges] {
375 Msg Info "Uploading badge image $badge_name.svg ...."
377 lassign [
ExecuteRet {*}$curl_cmd --request POST --header "PRIVATE-TOKEN: ${push_token}" --form "file=@$badge_name.svg" $api_url/projects/$project_id/uploads] ret content
378 set image_url [
ParseJSON $content full_path]
379 set image_url $gitlab_url/$image_url
380 if {[dict exists $current_badges $badge_name]} {
381 Msg Info "Badge $badge_name exists, updating it..."
382 set badge_id [
DictGet $current_badges $badge_name]
383 Execute curl --header "PRIVATE-TOKEN: $push_token" "$api_url/projects/${project_id}/badges/$badge_id" --request PUT --data "image_url=$image_url"
385 Msg Info "Badge $badge_name does not exist yet. Creating it..."
387 Execute curl --header "PRIVATE-TOKEN: $push_token" --request POST --data "link_url=$project_url/-/releases&image_url=$image_url&name=$badge_name" "$api_url/projects/$project_id/badges"