github.com/dmaizel/tests@v0.0.0-20210728163746-cae6a2d9cee8/metrics/report/report_dockerfile/fio-writes.R (about) 1 #!/usr/bin/env Rscript 2 # Copyright (c) 2018 Intel Corporation 3 # 4 # SPDX-License-Identifier: Apache-2.0 5 6 # Display details for 'fio' random writes storage IO tests. 7 8 9 library(ggplot2) # ability to plot nicely 10 library(gridExtra) # So we can plot multiple graphs together 11 suppressMessages(suppressWarnings(library(ggpubr))) # for ggtexttable 12 suppressMessages(library(jsonlite)) # to load the data 13 suppressMessages(suppressWarnings(library(tidyr))) # for gather 14 library(tibble) 15 16 testnames=c( 17 "fio-randwrite-128", 18 "fio-randwrite-256", 19 "fio-randwrite-512", 20 "fio-randwrite-1k", 21 "fio-randwrite-2k", 22 "fio-randwrite-4k", 23 "fio-randwrite-8k", 24 "fio-randwrite-16k", 25 "fio-randwrite-32k", 26 "fio-randwrite-64k" 27 ) 28 29 data2=c() 30 all_ldata=c() 31 all_ldata2=c() 32 stats=c() 33 rstats=c() 34 rstats_names=c() 35 36 37 # Where to store up the stats for the tables 38 write_bw_stats=c() 39 write_iops_stats=c() 40 write_lat95_stats=c() 41 write_lat99_stats=c() 42 43 # For each set of results 44 for (currentdir in resultdirs) { 45 bw_dirstats=c() 46 iops_dirstats=c() 47 lat95_dirstats=c() 48 lat99_dirstats=c() 49 # Derive the name from the test result dirname 50 datasetname=basename(currentdir) 51 52 for (testname in testnames) { 53 fname=paste(inputdir, currentdir, testname, '.json', sep="") 54 if ( !file.exists(fname)) { 55 #warning(paste("Skipping non-existent file: ", fname)) 56 next 57 } 58 59 # Import the data 60 fdata=fromJSON(fname) 61 # De-nest the test specific named data 62 fdata=fdata[[testname]] 63 64 blocksize=fdata$Raw$'global options'$bs 65 66 # Extract the latency data - it comes as a table of percentiles, so 67 # we have to do a little work... 68 clat=data.frame(clat_ns=fdata$Raw$jobs[[1]]$write$clat_ns$percentile) 69 70 # Generate a clat data set with 'clean' percentile numbers so 71 # we can sensibly plot it later on. 72 clat2=clat 73 colnames(clat2)<-sub("clat_ns.", "", colnames(clat2)) 74 colnames(clat2)<-sub("0000", "", colnames(clat2)) 75 ldata2=gather(clat2) 76 colnames(ldata2)[colnames(ldata2)=="key"] <- "percentile" 77 colnames(ldata2)[colnames(ldata2)=="value"] <- "ms" 78 ldata2$ms=ldata2$ms/1000000 #ns->ms 79 ldata2=cbind(ldata2, runtime=rep(datasetname, length(ldata2$percentile))) 80 ldata2=cbind(ldata2, blocksize=rep(blocksize, length(ldata2$percentile))) 81 82 # Pull the 95 and 99 percentiles for the boxplot diagram. 83 # Our values fall more in the range of ms... 84 pc95data=tibble(percentile=clat$clat_ns.95.000000/1000000) 85 pc95data=cbind(pc95data, runtime=rep(paste(datasetname, "95pc", sep="-"), length(pc95data$percentile))) 86 pc99data=tibble(percentile=clat$clat_ns.99.000000/1000000) 87 pc99data=cbind(pc99data, runtime=rep(paste(datasetname, "99pc", sep="-"), length(pc95data$percentile))) 88 ldata=rbind(pc95data, pc99data) 89 ldata=cbind(ldata, blocksize=rep(blocksize, length(ldata$percentile))) 90 91 # We want total bandwidth, so that is the sum of the bandwidths 92 # from all the write 'jobs'. 93 mdata=data.frame(write_bw_mps=as.numeric(sum(fdata$Raw$jobs[[1]]$write$bw)/1024)) 94 mdata=cbind(mdata, iops_tot=as.numeric(sum(fdata$Raw$jobs[[1]]$write$iops))) 95 mdata=cbind(mdata, runtime=rep(datasetname, length(mdata[, "write_bw_mps"]) )) 96 mdata=cbind(mdata, blocksize=rep(blocksize, length(mdata[, "write_bw_mps"]) )) 97 98 # Extract the stats tables 99 bw_dirstats=rbind(bw_dirstats, round(mdata$write_bw_mps, digits=1)) 100 # Rowname hack to get the blocksize recorded 101 rownames(bw_dirstats)[nrow(bw_dirstats)]=blocksize 102 103 iops_dirstats=rbind(iops_dirstats, round(mdata$iops_tot, digits=1)) 104 rownames(iops_dirstats)[nrow(iops_dirstats)]=blocksize 105 106 # And do the 95 and 99 percentiles as tables as well 107 lat95_dirstats=rbind(lat95_dirstats, round(mean(clat$clat_ns.95.000000)/1000000, digits=1)) 108 rownames(lat95_dirstats)[nrow(lat95_dirstats)]=blocksize 109 lat99_dirstats=rbind(lat99_dirstats, round(mean(clat$clat_ns.99.000000)/1000000, digits=1)) 110 rownames(lat99_dirstats)[nrow(lat99_dirstats)]=blocksize 111 112 # Store away as single sets 113 data2=rbind(data2, mdata) 114 all_ldata=rbind(all_ldata, ldata) 115 all_ldata2=rbind(all_ldata2, ldata2) 116 } 117 118 # Collect up for each dir we process into a column 119 write_bw_stats=cbind(write_bw_stats, bw_dirstats) 120 colnames(write_bw_stats)[ncol(write_bw_stats)]=datasetname 121 122 write_iops_stats=cbind(write_iops_stats, iops_dirstats) 123 colnames(write_iops_stats)[ncol(write_iops_stats)]=datasetname 124 125 write_lat95_stats=cbind(write_lat95_stats, lat95_dirstats) 126 colnames(write_lat95_stats)[ncol(write_lat95_stats)]=datasetname 127 write_lat99_stats=cbind(write_lat99_stats, lat99_dirstats) 128 colnames(write_lat99_stats)[ncol(write_lat99_stats)]=datasetname 129 } 130 131 # To get a nice looking table, we need to extract the rownames into their 132 # own column 133 write_bw_stats=cbind(Bandwidth=rownames(write_bw_stats), write_bw_stats) 134 write_bw_stats=cbind(write_bw_stats, Units=rep("MB/s", nrow(write_bw_stats))) 135 136 write_iops_stats=cbind(IOPS=rownames(write_iops_stats), write_iops_stats) 137 write_iops_stats=cbind(write_iops_stats, Units=rep("IOP/s", nrow(write_iops_stats))) 138 139 write_lat95_stats=cbind('lat 95pc'=rownames(write_lat95_stats), write_lat95_stats) 140 write_lat95_stats=cbind(write_lat95_stats, Units=rep("ms", nrow(write_lat95_stats))) 141 write_lat99_stats=cbind('lat 99pc'=rownames(write_lat99_stats), write_lat99_stats) 142 write_lat99_stats=cbind(write_lat99_stats, Units=rep("ms", nrow(write_lat99_stats))) 143 144 # lineplot of total bandwidth across blocksizes. 145 write_bw_line_plot <- ggplot() + 146 geom_line( data=data2, aes(blocksize, write_bw_mps, group=runtime, color=runtime)) + 147 ylim(0, NA) + 148 ggtitle("Random Write total bandwidth") + 149 xlab("Blocksize") + 150 ylab("Bandwidth (MiB/s)") + 151 theme( 152 axis.text.x=element_text(angle=90), 153 legend.position=c(0.35,0.8), 154 legend.title=element_text(size=5), 155 legend.text=element_text(size=5), 156 legend.background = element_rect(fill=alpha('blue', 0.2)) 157 ) 158 159 # lineplot of IOPS across blocksizes 160 write_iops_line_plot <- ggplot() + 161 geom_line( data=data2, aes(blocksize, iops_tot, group=runtime, color=runtime)) + 162 ylim(0, NA) + 163 ggtitle("Random Write total IOPS") + 164 xlab("Blocksize") + 165 ylab("IOPS") + 166 theme( 167 axis.text.x=element_text(angle=90), 168 legend.position=c(0.35,0.8), 169 legend.title=element_text(size=5), 170 legend.text=element_text(size=5), 171 legend.background = element_rect(fill=alpha('blue', 0.2)) 172 ) 173 174 # boxplot of 95 and 99 percentiles covering the parallel jobs, shown across 175 # the blocksizes. 176 write_clat_box_plot <- ggplot() + 177 geom_boxplot( data=all_ldata, aes(blocksize, percentile, color=runtime)) + 178 stat_summary( data=all_ldata, aes(blocksize, percentile, group=runtime, color=runtime), fun.y=mean, geom="line") + 179 ylim(0, NA) + 180 ggtitle("Random Write completion latency", subtitle="95&99 Percentiles, boxplot across jobs") + 181 xlab("Blocksize") + 182 ylab("Latency (ms)") + 183 theme(axis.text.x=element_text(angle=90)) + 184 # Use the 'paired' colour matrix as we are setting these up as pairs of 185 # 95 and 99 percentiles, and it is much easier to visually group those to 186 # each runtime if we use this colourmap. 187 scale_colour_brewer(palette="Paired") 188 189 190 # completion latency line plot across the percentiles, for a specific blocksize only 191 # as otherwise the graph would be far too noisy. 192 which_blocksize='4k' 193 clat_line_subtitle=paste("For blocksize", which_blocksize, sep=" ") 194 single_blocksize=subset(all_ldata2, blocksize==which_blocksize) 195 clat_line=aggregate( 196 single_blocksize$ms, 197 by=list( 198 percentile=single_blocksize$percentile, 199 blocksize=single_blocksize$blocksize, 200 runtime=single_blocksize$runtime 201 ), 202 FUN=mean 203 ) 204 205 clat_line$percentile=as.numeric(clat_line$percentile) 206 207 write_clat_line_plot <- ggplot() + 208 geom_line( data=clat_line, aes(percentile, x, group=runtime, color=runtime)) + 209 ylim(0, NA) + 210 ggtitle("Random Write completion latency percentiles", subtitle=clat_line_subtitle) + 211 xlab("Percentile") + 212 ylab("Time (ms)") + 213 theme( 214 axis.text.x=element_text(angle=90), 215 legend.position=c(0.35,0.8), 216 legend.title=element_text(size=5), 217 legend.text=element_text(size=5), 218 legend.background = element_rect(fill=alpha('blue', 0.2)) 219 ) 220 221 master_plot = grid.arrange( 222 write_bw_line_plot, 223 write_iops_line_plot, 224 write_clat_box_plot, 225 write_clat_line_plot, 226 nrow=2, 227 ncol=2 ) 228 229 # A bit of an odd tweak to force a pagebreak between the pictures and 230 # the tables. This only works because we have a `results='asis'` in the Rmd 231 # R fragment. 232 cat("\n\n\\pagebreak\n") 233 234 write_bw_stats_plot = suppressWarnings(ggtexttable(write_bw_stats, 235 theme=ttheme(base_size=10), 236 rows=NULL 237 )) 238 239 write_iops_stats_plot = suppressWarnings(ggtexttable(write_iops_stats, 240 theme=ttheme(base_size=10), 241 rows=NULL 242 )) 243 244 write_lat95_stats_plot = suppressWarnings(ggtexttable(write_lat95_stats, 245 theme=ttheme(base_size=10), 246 rows=NULL 247 )) 248 write_lat99_stats_plot = suppressWarnings(ggtexttable(write_lat99_stats, 249 theme=ttheme(base_size=10), 250 rows=NULL 251 )) 252 253 # and then the statistics tables 254 stats_plot = grid.arrange( 255 write_bw_stats_plot, 256 write_iops_stats_plot, 257 write_lat95_stats_plot, 258 write_lat99_stats_plot, 259 nrow=4, 260 ncol=1 )