diff --git a/metrics/report/report_dockerfile/collectd_scaling.R b/metrics/report/report_dockerfile/collectd_scaling.R index 88e65bf..2365364 100755 --- a/metrics/report/report_dockerfile/collectd_scaling.R +++ b/metrics/report/report_dockerfile/collectd_scaling.R @@ -13,692 +13,710 @@ suppressMessages(library(jsonlite)) # to load the data. suppressMessages(library(scales)) # For de-science notation of axis library(tibble) # tibbles for tidy data -testnames=c( - "k8s-rapid.*" -) -podbootdata=c() # Track per-launch data -cpuidledata=c() # Track cpu idle data per nodes -memfreedata=c() # Track mem free data for nodes -inodefreedata=c() # Track inode free data for nodes -ifpacketdata=c() # Track interface packet data for nodes -ifoctetdata=c() # Track interface octets data for nodes -ifdropdata=c() # Track interface dropped data for nodes -iferrordata=c() # Track interface errors data for nodes -memstats=c() # Statistics for memory usage -cpustats=c() # Statistics for cpu usage -bootstats=c() # Statistics for boot (launch) times -inodestats=c() # Statistics for inode usage +render_collectd_scaling <- function() +{ + testnames=c( + "k8s-rapid.*" + ) -# iterate over every set of results (test run) -for (currentdir in resultdirs) { - # For every results file we are interested in evaluating - for (testname in testnames) { - matchdir=paste(inputdir, currentdir, sep="") - matchfile=paste(testname, '\\.json', sep="") - files=list.files(matchdir, pattern=matchfile) - if ( length(files) == 0 ) { - #warning(paste("Pattern [", matchdir, "/", matchfile, "] matched nothing")) - } + podbootdata=c() # Track per-launch data + cpuidledata=c() # Track cpu idle data per nodes + memfreedata=c() # Track mem free data for nodes + inodefreedata=c() # Track inode free data for nodes + ifpacketdata=c() # Track interface packet data for nodes + ifoctetdata=c() # Track interface octets data for nodes + ifdropdata=c() # Track interface dropped data for nodes + iferrordata=c() # Track interface errors data for nodes + memstats=c() # Statistics for memory usage + cpustats=c() # Statistics for cpu usage + bootstats=c() # Statistics for boot (launch) times + inodestats=c() # Statistics for inode usage - # For every matching results file - for (ffound in files) { - fname=paste(inputdir, currentdir, ffound, sep="") - if ( !file.exists(fname)) { - warning(paste("Skipping non-existent file: ", fname)) - next - } - # Derive the name from the test result dirname - datasetname=basename(currentdir) - - # Import the data - fdata=fromJSON(fname) - - # determine whether NoSchedule taint is present for each node - # from the 'kubectl get nodes' data dump in the json - node_sched_data=list() - nodes=c() - num_nodes=nrow(fdata$'kubectl-get-nodes'$items) - for(n in seq(num_nodes)){ - json_node=fdata$'kubectl-get-nodes'$items[n,] - json_node_name=json_node$metadata$name - taints=data.frame(json_node$spec$taints) - nosched = "false" - if(nrow(taints) > 0) { - for(t in seq(nrow(taints))){ - if(taints[t,]$effect == "NoSchedule") { - nosched = "true" - break - } - } - } - node_sched_data[json_node_name] = nosched + # iterate over every set of results (test run) + for (currentdir in resultdirs) { + # For every results file we are interested in evaluating + for (testname in testnames) { + matchdir=paste(inputdir, currentdir, sep="") + matchfile=paste(testname, '\\.json', sep="") + files=list.files(matchdir, pattern=matchfile) + if ( length(files) == 0 ) { + #warning(paste("Pattern [", matchdir, "/", matchfile, "] matched nothing")) } - # De-nest the test name specific data - shortname=substr(ffound, 1, nchar(ffound)-nchar(".json")) - fdata=fdata[[shortname]] - testname=datasetname - - # Most of the data we are looking for comes in BootResults, so pick it out to make - # referencing easier - br=fdata$BootResults - - ######################################################## - #### Now extract all the pod launch boot data items #### - ######################################################## - local_bootdata=tibble(launch_time=br$launch_time$Result) - local_bootdata=cbind(local_bootdata, n_pods=br$n_pods$Result) - local_bootdata=cbind(local_bootdata, testname=rep(testname, length(local_bootdata$n_pods))) - local_bootdata=cbind(local_bootdata, ns=br$date$ns) - # get the epoch time in seconds for the boot - local_bootdata$epoch = local_bootdata$ns/1000000000 - local_bootdata$s_offset = local_bootdata$epoch - local_bootdata[1,]$epoch - - # Now Calculate some stats. This gets more complicated as we may have n-nodes, - # and we want to show a 'pod average', so we try to assess for all nodes. If - # we have different 'size' nodes in a cluster, that could throw out the result, - # but the only other option would be to try and show every node separately in the - # table. - - # Get a list of all the nodes from the schedule data list - nodes=names(node_sched_data) - - memtotal=0 - cputotal=0 - inodetotal=0 - cpu_idle_data=c() - mem_free_data=c() - inode_free_data=c() - interface_packets_data=c() - interface_octets_data=c() - interface_dropped_data=c() - interface_errors_data=c() - # Calculate per-node totals, and tot them up to a global total. - for (n in nodes) { - # check if collectd node data has been untarred yet, if not untar - node_dir=paste(inputdir, currentdir, n, sep="") - if ( !file.exists(node_dir)) { - node_tar=paste(inputdir, currentdir, n, ".tar.gz", sep="") - system(paste("mkdir -p", node_dir)) - system(paste("tar -xzf", node_tar, "-C", node_dir)) - } - # all collectd data is under localhost/ - localhost_dir=paste(node_dir, "localhost", sep="/") - - # grab memory data - memory_dir=paste(localhost_dir, "memory", sep="/") - # filename has date on the end, so look for the right file name - freemem_pattern='^memory\\-free' - files=list.files(memory_dir, pattern=freemem_pattern) - # collectd csv plugin starts a new file for each day of data collected - for(file in files) { - mem_free_csv=paste(memory_dir, file, sep="/") - node_mem_free_data=read.csv(mem_free_csv, header=TRUE, sep=",") - node_mem_free_data=cbind(node_mem_free_data, - node=rep(n, length(node_mem_free_data$value))) - node_mem_free_data=cbind(node_mem_free_data, - testname=rep(testname, length(node_mem_free_data$value))) - node_mem_free_data$s_offset = node_mem_free_data$epoch - local_bootdata[1,]$epoch - - mem_free_data=rbind(mem_free_data, node_mem_free_data) - } - - # grab CPU data - cpu_dir=paste(localhost_dir, "aggregation-cpu-average", sep="/") - # filename has date on the end, so look for the right file name - percent_idle_pattern='^percent\\-idle' - files=list.files(cpu_dir, pattern=percent_idle_pattern) - for(file in files) { - cpu_idle_csv=paste(cpu_dir, file, sep="/") - node_cpu_idle_data=read.csv(cpu_idle_csv, header=TRUE, sep=",") - node_cpu_idle_data=cbind(node_cpu_idle_data, - node=rep(n, length(node_cpu_idle_data$value))) - node_cpu_idle_data=cbind(node_cpu_idle_data, - testname=rep(testname, length(node_cpu_idle_data$value))) - node_cpu_idle_data$s_offset = node_cpu_idle_data$epoch - local_bootdata[1,]$epoch - - cpu_idle_data=rbind(cpu_idle_data, node_cpu_idle_data) - } - - # grab inode data - inode_dir=paste(localhost_dir, "df-root", sep="/") - # filename has date on the end, so look for the right file name - inode_free_pattern='^df_inodes\\-free' - files=list.files(inode_dir, pattern=inode_free_pattern) - for(file in files) { - inode_free_csv=paste(inode_dir, file, sep="/") - node_inode_free_data=read.csv(inode_free_csv, header=TRUE, sep=",") - node_inode_free_data=cbind(node_inode_free_data, - node=rep(n, length(node_inode_free_data$value))) - node_inode_free_data=cbind(node_inode_free_data, - testname=rep(testname, length(node_inode_free_data$value))) - node_inode_free_data$s_offset = node_inode_free_data$epoch - local_bootdata[1,]$epoch - - inode_free_data=rbind(inode_free_data, node_inode_free_data) - } - - # grab interface data - interface_dir_pattern='^interface\\-' - files=list.files(localhost_dir, pattern=interface_dir_pattern) - for (file in files) { - interface_dir=paste(localhost_dir, file, sep="/") - interface_name=substr(file, nchar("interface-")+1, nchar(file)) - - # filename has date on the end, so look for the right file name - interface_packets_pattern='^if_packets' - int_files=list.files(interface_dir, pattern=interface_packets_pattern) - for (int_file in int_files) { - interface_packets_csv=paste(interface_dir, int_file, sep="/") - node_interface_packets_data=read.csv(interface_packets_csv, header=TRUE, sep=",") - node_interface_packets_data=cbind(node_interface_packets_data, - node=rep(n, length(node_interface_packets_data$epoch))) - node_interface_packets_data=cbind(node_interface_packets_data, - testname=rep(testname, - length(node_interface_packets_data$epoch))) - node_interface_packets_data=cbind(node_interface_packets_data, - name=rep(interface_name, - length(node_interface_packets_data$epoch))) - node_interface_packets_data$s_offset = node_interface_packets_data$epoch - local_bootdata[1,]$epoch - - interface_packets_data=rbind(interface_packets_data, node_interface_packets_data) - } - - # filename has date on the end, so look for the right file name - interface_octets_pattern='^if_octets' - int_files=list.files(interface_dir, pattern=interface_octets_pattern) - for (int_file in int_files) { - interface_octets_csv=paste(interface_dir, int_file, sep="/") - node_interface_octets_data=read.csv(interface_octets_csv, header=TRUE, sep=",") - node_interface_octets_data=cbind(node_interface_octets_data, - node=rep(n, length(node_interface_octets_data$epoch))) - node_interface_octets_data=cbind(node_interface_octets_data, - testname=rep(testname, - length(node_interface_octets_data$epoch))) - node_interface_octets_data=cbind(node_interface_octets_data, - name=rep(interface_name, - length(node_interface_octets_data$epoch))) - node_interface_octets_data$s_offset = node_interface_octets_data$epoch - local_bootdata[1,]$epoch - - interface_octets_data=rbind(interface_octets_data, node_interface_octets_data) - } - - # filename has date on the end, so look for the right file name - interface_dropped_pattern='^if_dropped' - int_files=list.files(interface_dir, pattern=interface_dropped_pattern) - for (int_file in int_files) { - interface_dropped_csv=paste(interface_dir, int_file, sep="/") - node_interface_dropped_data=read.csv(interface_dropped_csv, header=TRUE, sep=",") - node_interface_dropped_data=cbind(node_interface_dropped_data, - node=rep(n, length(node_interface_dropped_data$epoch))) - node_interface_dropped_data=cbind(node_interface_dropped_data, - testname=rep(testname, - length(node_interface_dropped_data$epoch))) - node_interface_dropped_data=cbind(node_interface_dropped_data, - name=rep(interface_name, - length(node_interface_dropped_data$epoch))) - node_interface_dropped_data$s_offset = node_interface_dropped_data$epoch - local_bootdata[1,]$epoch - - interface_dropped_data=rbind(interface_dropped_data, node_interface_dropped_data) - } - - # filename has date on the end, so look for the right file name - interface_errors_pattern='^if_errors' - int_files=list.files(interface_dir, pattern=interface_errors_pattern) - for (int_file in int_files) { - interface_errors_csv=paste(interface_dir, int_file, sep="/") - node_interface_errors_data=read.csv(interface_errors_csv, header=TRUE, sep=",") - node_interface_errors_data=cbind(node_interface_errors_data, - node=rep(n, length(node_interface_errors_data$epoch))) - node_interface_errors_data=cbind(node_interface_errors_data, - testname=rep(testname, - length(node_interface_errors_data$epoch))) - node_interface_errors_data=cbind(node_interface_errors_data, - name=rep(interface_name, - length(node_interface_errors_data$epoch))) - node_interface_errors_data$s_offset = node_interface_errors_data$epoch - local_bootdata[1,]$epoch - - interface_errors_data=rbind(interface_errors_data, node_interface_errors_data) - } - } - - # Do not use the master (non-schedulable) nodes to calculate - # launched pod metrics - if(node_sched_data[n] == "true") { + # For every matching results file + for (ffound in files) { + fname=paste(inputdir, currentdir, ffound, sep="") + if ( !file.exists(fname)) { + warning(paste("Skipping non-existent file: ", fname)) next } + # Derive the name from the test result dirname + datasetname=basename(currentdir) - # get the epoch time of first and last pod launch - start_time=local_bootdata$epoch[1] - end_time=local_bootdata$epoch[length(local_bootdata$epoch)] + # Import the data + fdata=fromJSON(fname) - # get value closest to first pod launch - mem_start_index=Position(function(x) x > start_time, node_mem_free_data$epoch) - # take the reading previous to the index as long as a valid index - if (is.na(mem_start_index)) { - mem_start_index = 1 - } else if (mem_start_index > 1) { - mem_start_index = mem_start_index - 1 + # determine whether NoSchedule taint is present for each node + # from the 'kubectl get nodes' data dump in the json + node_sched_data=list() + nodes=c() + num_nodes=nrow(fdata$'kubectl-get-nodes'$items) + for(n in seq(num_nodes)){ + json_node=fdata$'kubectl-get-nodes'$items[n,] + json_node_name=json_node$metadata$name + taints=data.frame(json_node$spec$taints) + nosched = "false" + if(nrow(taints) > 0) { + for(t in seq(nrow(taints))){ + if(taints[t,]$effect == "NoSchedule") { + nosched = "true" + break + } + } + } + node_sched_data[json_node_name] = nosched } - max_free_mem=node_mem_free_data$value[mem_start_index] - # get value closest to last pod launch - mem_end_index=Position(function(x) x > end_time, node_mem_free_data$epoch) - # take the reading previous to the index as long as a valid index - if (is.na(mem_end_index)) { - mem_end_index = length(node_mem_free_data$epoch) - } else if (mem_end_index > 1) { - mem_end_index = mem_end_index - 1 + # De-nest the test name specific data + shortname=substr(ffound, 1, nchar(ffound)-nchar(".json")) + fdata=fdata[[shortname]] + testname=datasetname + + # Most of the data we are looking for comes in BootResults, so pick it out to make + # referencing easier + br=fdata$BootResults + + ######################################################## + #### Now extract all the pod launch boot data items #### + ######################################################## + local_bootdata=tibble(launch_time=br$launch_time$Result) + local_bootdata=cbind(local_bootdata, n_pods=br$n_pods$Result) + local_bootdata=cbind(local_bootdata, testname=rep(testname, length(local_bootdata$n_pods))) + local_bootdata=cbind(local_bootdata, ns=br$date$ns) + # get the epoch time in seconds for the boot + local_bootdata$epoch = local_bootdata$ns/1000000000 + local_bootdata$s_offset = local_bootdata$epoch - local_bootdata[1,]$epoch + + # Now Calculate some stats. This gets more complicated as we may have n-nodes, + # and we want to show a 'pod average', so we try to assess for all nodes. If + # we have different 'size' nodes in a cluster, that could throw out the result, + # but the only other option would be to try and show every node separately in the + # table. + + # Get a list of all the nodes from the schedule data list + nodes=names(node_sched_data) + + memtotal=0 + cputotal=0 + inodetotal=0 + cpu_idle_data=c() + mem_free_data=c() + inode_free_data=c() + interface_packets_data=c() + interface_octets_data=c() + interface_dropped_data=c() + interface_errors_data=c() + # Calculate per-node totals, and tot them up to a global total. + for (n in nodes) { + # check if collectd node data has been untarred yet, if not untar + node_dir=paste(inputdir, currentdir, n, sep="") + if ( !file.exists(node_dir)) { + node_tar=paste(inputdir, currentdir, n, ".tar.gz", sep="") + system(paste("mkdir -p", node_dir)) + system(paste("tar -xzf", node_tar, "-C", node_dir)) + } + # all collectd data is under localhost/ + localhost_dir=paste(node_dir, "localhost", sep="/") + + # grab memory data + memory_dir=paste(localhost_dir, "memory", sep="/") + # filename has date on the end, so look for the right file name + freemem_pattern='^memory\\-free' + files=list.files(memory_dir, pattern=freemem_pattern) + # collectd csv plugin starts a new file for each day of data collected + for(file in files) { + mem_free_csv=paste(memory_dir, file, sep="/") + node_mem_free_data=read.csv(mem_free_csv, header=TRUE, sep=",") + node_mem_free_data=cbind(node_mem_free_data, + node=rep(n, length(node_mem_free_data$value))) + node_mem_free_data=cbind(node_mem_free_data, + testname=rep(testname, length(node_mem_free_data$value))) + node_mem_free_data$s_offset = node_mem_free_data$epoch - local_bootdata[1,]$epoch + + mem_free_data=rbind(mem_free_data, node_mem_free_data) + } + + # grab CPU data + cpu_dir=paste(localhost_dir, "aggregation-cpu-average", sep="/") + # filename has date on the end, so look for the right file name + percent_idle_pattern='^percent\\-idle' + files=list.files(cpu_dir, pattern=percent_idle_pattern) + for(file in files) { + cpu_idle_csv=paste(cpu_dir, file, sep="/") + node_cpu_idle_data=read.csv(cpu_idle_csv, header=TRUE, sep=",") + node_cpu_idle_data=cbind(node_cpu_idle_data, + node=rep(n, length(node_cpu_idle_data$value))) + node_cpu_idle_data=cbind(node_cpu_idle_data, + testname=rep(testname, length(node_cpu_idle_data$value))) + node_cpu_idle_data$s_offset = node_cpu_idle_data$epoch - local_bootdata[1,]$epoch + + cpu_idle_data=rbind(cpu_idle_data, node_cpu_idle_data) + } + + # grab inode data + inode_dir=paste(localhost_dir, "df-root", sep="/") + # filename has date on the end, so look for the right file name + inode_free_pattern='^df_inodes\\-free' + files=list.files(inode_dir, pattern=inode_free_pattern) + for(file in files) { + inode_free_csv=paste(inode_dir, file, sep="/") + node_inode_free_data=read.csv(inode_free_csv, header=TRUE, sep=",") + node_inode_free_data=cbind(node_inode_free_data, + node=rep(n, length(node_inode_free_data$value))) + node_inode_free_data=cbind(node_inode_free_data, + testname=rep(testname, length(node_inode_free_data$value))) + node_inode_free_data$s_offset = node_inode_free_data$epoch - local_bootdata[1,]$epoch + + inode_free_data=rbind(inode_free_data, node_inode_free_data) + } + + # grab interface data + interface_dir_pattern='^interface\\-' + files=list.files(localhost_dir, pattern=interface_dir_pattern) + for (file in files) { + interface_dir=paste(localhost_dir, file, sep="/") + interface_name=substr(file, nchar("interface-")+1, nchar(file)) + + # filename has date on the end, so look for the right file name + interface_packets_pattern='^if_packets' + int_files=list.files(interface_dir, pattern=interface_packets_pattern) + for (int_file in int_files) { + interface_packets_csv=paste(interface_dir, int_file, sep="/") + node_interface_packets_data=read.csv(interface_packets_csv, header=TRUE, sep=",") + node_interface_packets_data=cbind(node_interface_packets_data, + node=rep(n, length(node_interface_packets_data$epoch))) + node_interface_packets_data=cbind(node_interface_packets_data, + testname=rep(testname, + length(node_interface_packets_data$epoch))) + node_interface_packets_data=cbind(node_interface_packets_data, + name=rep(interface_name, + length(node_interface_packets_data$epoch))) + node_interface_packets_data$s_offset = node_interface_packets_data$epoch - local_bootdata[1,]$epoch + + interface_packets_data=rbind(interface_packets_data, node_interface_packets_data) + } + + # filename has date on the end, so look for the right file name + interface_octets_pattern='^if_octets' + int_files=list.files(interface_dir, pattern=interface_octets_pattern) + for (int_file in int_files) { + interface_octets_csv=paste(interface_dir, int_file, sep="/") + node_interface_octets_data=read.csv(interface_octets_csv, header=TRUE, sep=",") + node_interface_octets_data=cbind(node_interface_octets_data, + node=rep(n, length(node_interface_octets_data$epoch))) + node_interface_octets_data=cbind(node_interface_octets_data, + testname=rep(testname, + length(node_interface_octets_data$epoch))) + node_interface_octets_data=cbind(node_interface_octets_data, + name=rep(interface_name, + length(node_interface_octets_data$epoch))) + node_interface_octets_data$s_offset = node_interface_octets_data$epoch - local_bootdata[1,]$epoch + + interface_octets_data=rbind(interface_octets_data, node_interface_octets_data) + } + + # filename has date on the end, so look for the right file name + interface_dropped_pattern='^if_dropped' + int_files=list.files(interface_dir, pattern=interface_dropped_pattern) + for (int_file in int_files) { + interface_dropped_csv=paste(interface_dir, int_file, sep="/") + node_interface_dropped_data=read.csv(interface_dropped_csv, header=TRUE, sep=",") + node_interface_dropped_data=cbind(node_interface_dropped_data, + node=rep(n, length(node_interface_dropped_data$epoch))) + node_interface_dropped_data=cbind(node_interface_dropped_data, + testname=rep(testname, + length(node_interface_dropped_data$epoch))) + node_interface_dropped_data=cbind(node_interface_dropped_data, + name=rep(interface_name, + length(node_interface_dropped_data$epoch))) + node_interface_dropped_data$s_offset = node_interface_dropped_data$epoch - local_bootdata[1,]$epoch + + interface_dropped_data=rbind(interface_dropped_data, node_interface_dropped_data) + } + + # filename has date on the end, so look for the right file name + interface_errors_pattern='^if_errors' + int_files=list.files(interface_dir, pattern=interface_errors_pattern) + for (int_file in int_files) { + interface_errors_csv=paste(interface_dir, int_file, sep="/") + node_interface_errors_data=read.csv(interface_errors_csv, header=TRUE, sep=",") + node_interface_errors_data=cbind(node_interface_errors_data, + node=rep(n, length(node_interface_errors_data$epoch))) + node_interface_errors_data=cbind(node_interface_errors_data, + testname=rep(testname, + length(node_interface_errors_data$epoch))) + node_interface_errors_data=cbind(node_interface_errors_data, + name=rep(interface_name, + length(node_interface_errors_data$epoch))) + node_interface_errors_data$s_offset = node_interface_errors_data$epoch - local_bootdata[1,]$epoch + + interface_errors_data=rbind(interface_errors_data, node_interface_errors_data) + } + } + + # Do not use the master (non-schedulable) nodes to calculate + # launched pod metrics + if(node_sched_data[n] == "true") { + next + } + + # get the epoch time of first and last pod launch + start_time=local_bootdata$epoch[1] + end_time=local_bootdata$epoch[length(local_bootdata$epoch)] + + # get value closest to first pod launch + mem_start_index=Position(function(x) x > start_time, node_mem_free_data$epoch) + # take the reading previous to the index as long as a valid index + if (is.na(mem_start_index)) { + mem_start_index = 1 + } else if (mem_start_index > 1) { + mem_start_index = mem_start_index - 1 + } + max_free_mem=node_mem_free_data$value[mem_start_index] + + # get value closest to last pod launch + mem_end_index=Position(function(x) x > end_time, node_mem_free_data$epoch) + # take the reading previous to the index as long as a valid index + if (is.na(mem_end_index)) { + mem_end_index = length(node_mem_free_data$epoch) + } else if (mem_end_index > 1) { + mem_end_index = mem_end_index - 1 + } + min_free_mem=node_mem_free_data$value[mem_end_index] + + memtotal = memtotal + (max_free_mem - min_free_mem) + + # get value closest to first pod launch + cpu_start_index=Position(function(x) x > start_time, node_cpu_idle_data$epoch) + # take the reading previous to the index as long as a valid index + if (is.na(cpu_start_index)) { + cpu_start_index = 1 + } else if (cpu_start_index > 1) { + cpu_start_index = cpu_start_index - 1 + } + max_idle_cpu=node_cpu_idle_data$value[cpu_start_index] + + # get value closest to last pod launch + cpu_end_index=Position(function(x) x > end_time, node_cpu_idle_data$epoch) + # take the reading previous to the index as long as a valid index + if (is.na(cpu_end_index)) { + cpu_end_index = length(node_cpu_idle_data$epoch) + } else if (cpu_end_index > 1) { + cpu_end_index = cpu_end_index - 1 + } + min_idle_cpu=node_cpu_idle_data$value[cpu_end_index] + + cputotal = cputotal + (max_idle_cpu - min_idle_cpu) + + # get value closest to first pod launch + inode_start_index=Position(function(x) x > start_time, node_inode_free_data$epoch) + # take the reading previous to the index as long as a valid index + if (is.na(inode_start_index)) { + inode_start_index = 1 + } else if (inode_start_index > 1) { + inode_start_index = inode_start_index - 1 + } + max_free_inode=node_inode_free_data$value[inode_start_index] + + # get value closest to last pod launch + inode_end_index=Position(function(x) x > end_time, node_inode_free_data$epoch) + # take the reading previous to the index as long as a valid index + if (is.na(inode_end_index)) { + inode_end_index = length(node_cpu_idle_data$epoch) + } else if (inode_end_index > 1) { + inode_end_index = inode_end_index - 1 + } + min_free_inode=node_inode_free_data$value[inode_end_index] + + inodetotal = inodetotal + (max_free_inode - min_free_inode) } - min_free_mem=node_mem_free_data$value[mem_end_index] - memtotal = memtotal + (max_free_mem - min_free_mem) + num_pods = local_bootdata$n_pods[length(local_bootdata$n_pods)] - # get value closest to first pod launch - cpu_start_index=Position(function(x) x > start_time, node_cpu_idle_data$epoch) - # take the reading previous to the index as long as a valid index - if (is.na(cpu_start_index)) { - cpu_start_index = 1 - } else if (cpu_start_index > 1) { - cpu_start_index = cpu_start_index - 1 - } - max_idle_cpu=node_cpu_idle_data$value[cpu_start_index] + # We get data in b, but want the graphs in Gb. + memtotal = memtotal / (1024*1024*1024) + gb_per_pod = memtotal/num_pods + pod_per_gb = 1/gb_per_pod - # get value closest to last pod launch - cpu_end_index=Position(function(x) x > end_time, node_cpu_idle_data$epoch) - # take the reading previous to the index as long as a valid index - if (is.na(cpu_end_index)) { - cpu_end_index = length(node_cpu_idle_data$epoch) - } else if (cpu_end_index > 1) { - cpu_end_index = cpu_end_index - 1 - } - min_idle_cpu=node_cpu_idle_data$value[cpu_end_index] + # Memory usage stats. + local_mems = c( + "Test"=testname, + "n"=num_pods, + "Tot_Gb"=round(memtotal, 3), + "avg_Gb"=round(gb_per_pod, 4), + "n_per_Gb"=round(pod_per_gb, 2) + ) + memstats=rbind(memstats, local_mems) - cputotal = cputotal + (max_idle_cpu - min_idle_cpu) + # cpu usage stats + local_cpus = c( + "Test"=testname, + "n"=num_pods, + "Tot_CPU"=round(cputotal, 3), + "avg_CPU"=round(cputotal/num_pods, 4) + ) + cpustats=rbind(cpustats, local_cpus) - # get value closest to first pod launch - inode_start_index=Position(function(x) x > start_time, node_inode_free_data$epoch) - # take the reading previous to the index as long as a valid index - if (is.na(inode_start_index)) { - inode_start_index = 1 - } else if (inode_start_index > 1) { - inode_start_index = inode_start_index - 1 - } - max_free_inode=node_inode_free_data$value[inode_start_index] + # launch (boot) stats + local_boots = c( + "Test"=testname, + "n"=num_pods, + "median"=median(na.omit(local_bootdata)$launch_time)/1000, + "min"=min(na.omit(local_bootdata)$launch_time)/1000, + "max"=max(na.omit(local_bootdata)$launch_time)/1000, + "sd"=round(sd(na.omit(local_bootdata)$launch_time)/1000, 4) + ) - # get value closest to last pod launch - inode_end_index=Position(function(x) x > end_time, node_inode_free_data$epoch) - # take the reading previous to the index as long as a valid index - if (is.na(inode_end_index)) { - inode_end_index = length(node_cpu_idle_data$epoch) - } else if (inode_end_index > 1) { - inode_end_index = inode_end_index - 1 - } - min_free_inode=node_inode_free_data$value[inode_end_index] + bootstats=rbind(bootstats, local_boots) - inodetotal = inodetotal + (max_free_inode - min_free_inode) + # inode stats + local_inodes = c( + "Test"=testname, + "n"=num_pods, + "Tot_inode"=round(inodetotal, 3), + "avg_inode"=round(inodetotal/num_pods, 4) + ) + inodestats=rbind(inodestats, local_inodes) + + # And collect up our rows into our global table of all results + # These two tables *should* be the source of all the data we need to + # process and plot (apart from the stats....) + podbootdata=rbind(podbootdata, local_bootdata, make.row.names=FALSE) + cpuidledata=rbind(cpuidledata, cpu_idle_data) + memfreedata=rbind(memfreedata, mem_free_data) + inodefreedata=rbind(inodefreedata, inode_free_data) + ifpacketdata=rbind(ifpacketdata, interface_packets_data) + ifoctetdata=rbind(ifoctetdata, interface_octets_data) + ifdropdata=rbind(ifdropdata, interface_dropped_data) + iferrordata=rbind(iferrordata, interface_errors_data) } - - num_pods = local_bootdata$n_pods[length(local_bootdata$n_pods)] - - # We get data in b, but want the graphs in Gb. - memtotal = memtotal / (1024*1024*1024) - gb_per_pod = memtotal/num_pods - pod_per_gb = 1/gb_per_pod - - # Memory usage stats. - local_mems = c( - "Test"=testname, - "n"=num_pods, - "Tot_Gb"=round(memtotal, 3), - "avg_Gb"=round(gb_per_pod, 4), - "n_per_Gb"=round(pod_per_gb, 2) - ) - memstats=rbind(memstats, local_mems) - - # cpu usage stats - local_cpus = c( - "Test"=testname, - "n"=num_pods, - "Tot_CPU"=round(cputotal, 3), - "avg_CPU"=round(cputotal/num_pods, 4) - ) - cpustats=rbind(cpustats, local_cpus) - - # launch (boot) stats - local_boots = c( - "Test"=testname, - "n"=num_pods, - "median"=median(na.omit(local_bootdata)$launch_time)/1000, - "min"=min(na.omit(local_bootdata)$launch_time)/1000, - "max"=max(na.omit(local_bootdata)$launch_time)/1000, - "sd"=round(sd(na.omit(local_bootdata)$launch_time)/1000, 4) - ) - - bootstats=rbind(bootstats, local_boots) - - # inode stats - local_inodes = c( - "Test"=testname, - "n"=num_pods, - "Tot_inode"=round(inodetotal, 3), - "avg_inode"=round(inodetotal/num_pods, 4) - ) - inodestats=rbind(inodestats, local_inodes) } - - # And collect up our rows into our global table of all results - # These two tables *should* be the source of all the data we need to - # process and plot (apart from the stats....) - podbootdata=rbind(podbootdata, local_bootdata, make.row.names=FALSE) - cpuidledata=rbind(cpuidledata, cpu_idle_data) - memfreedata=rbind(memfreedata, mem_free_data) - inodefreedata=rbind(inodefreedata, inode_free_data) - ifpacketdata=rbind(ifpacketdata, interface_packets_data) - ifoctetdata=rbind(ifoctetdata, interface_octets_data) - ifdropdata=rbind(ifdropdata, interface_dropped_data) - iferrordata=rbind(iferrordata, interface_errors_data) } + + # Check we actually found some JSON results files. + if ( length(bootstats) == 0 ) { + cat("No results files found for rapid scaling tests\n\n") + return() + } + + # And then check we found at least some matching node collectd data. + if ( length(memfreedata) == 0 ) { + cat("No collectd data found for rapid scaling tests\n\n") + return() + } + + # It's nice to show the graphs in Gb, at least for any decent sized test + # run, so make a new column with that pre-divided data in it for us to use. + memfreedata$mem_free_gb = memfreedata$value/(1024*1024*1024) + # And show the boot times in seconds, not ms + podbootdata$launch_time_s = podbootdata$launch_time/1000.0 + + + ########### Output memory page ############## + mem_stats_plot = suppressWarnings(ggtexttable(data.frame(memstats), + theme=ttheme(base_size=10), + rows=NULL + )) + + mem_scale = (max(memfreedata$value) / (1024*1024*1024)) / max(podbootdata$n_pods) + mem_line_plot <- ggplot() + + geom_line(data=memfreedata, + aes(s_offset, mem_free_gb, colour=interaction(testname, node), + group=interaction(testname, node)), + alpha=0.3) + + geom_point(data=memfreedata, + aes(s_offset, mem_free_gb, colour=interaction(testname, node), + group=interaction(testname, node)), + alpha=0.5, size=0.5) + + geom_line(data=podbootdata, + aes(x=s_offset, y=n_pods*mem_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.2) + + geom_point(data=podbootdata, + aes(x=s_offset, y=n_pods*mem_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.3, size=0.5) + + labs(colour="") + + xlab("seconds") + + ylab("System Avail (Gb)") + + scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./mem_scale, name="pods")) + + ggtitle("System Memory free") + + theme(legend.position="bottom") + + theme(axis.text.x=element_text(angle=90)) + + page1 = grid.arrange( + mem_line_plot, + mem_stats_plot, + ncol=1 + ) + + # pagebreak, as the graphs overflow the page otherwise + cat("\n\n\\pagebreak\n") + + ########## Output cpu page ############## + cpu_stats_plot = suppressWarnings(ggtexttable(data.frame(cpustats), + theme=ttheme(base_size=10), + rows=NULL + )) + + cpu_scale = max(cpuidledata$value) / max(podbootdata$n_pods) + cpu_line_plot <- ggplot() + + geom_line(data=cpuidledata, + aes(x=s_offset, y=value, colour=interaction(testname, node), + group=interaction(testname, node)), + alpha=0.3) + + geom_point(data=cpuidledata, + aes(x=s_offset, y=value, colour=interaction(testname, node), + group=interaction(testname, node)), + alpha=0.5, size=0.5) + + geom_line(data=podbootdata, + aes(x=s_offset, y=n_pods*cpu_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.2) + + geom_point(data=podbootdata, + aes(x=s_offset, y=n_pods*cpu_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.3, size=0.5) + + labs(colour="") + + scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./cpu_scale, name="pods")) + + xlab("seconds") + + ylab("System CPU Idle (%)") + + ggtitle("System CPU usage") + + theme(legend.position="bottom") + + theme(axis.text.x=element_text(angle=90)) + + page2 = grid.arrange( + cpu_line_plot, + cpu_stats_plot, + ncol=1 + ) + + # pagebreak, as the graphs overflow the page otherwise + cat("\n\n\\pagebreak\n") + + ########## Output boot page ############## + boot_stats_plot = suppressWarnings(ggtexttable(data.frame(bootstats), + theme=ttheme(base_size=10), + rows=NULL + )) + + boot_line_plot <- ggplot() + + geom_line(data=podbootdata, + aes(n_pods, launch_time_s, colour=testname, group=testname), + alpha=0.2) + + xlab("pods") + + ylab("Boot time (s)") + + ggtitle("Pod boot time") + + theme(legend.position="bottom") + + theme(axis.text.x=element_text(angle=90)) + + page3 = grid.arrange( + boot_line_plot, + boot_stats_plot, + ncol=1 + ) + + # pagebreak, as the graphs overflow the page otherwise + cat("\n\n\\pagebreak\n") + + ########## Output inode page ############## + inode_stats_plot = suppressWarnings(ggtexttable(data.frame(inodestats), + theme=ttheme(base_size=10), + rows=NULL + )) + + inode_scale = max(inodefreedata$value) / max(podbootdata$n_pods) + inode_line_plot <- ggplot() + + geom_line(data=inodefreedata, + aes(x=s_offset, y=value, colour=interaction(testname, node), + group=interaction(testname, node)), + alpha=0.2) + + geom_point(data=inodefreedata, + aes(x=s_offset, y=value, colour=interaction(testname, node), + group=interaction(testname, node)), + alpha=0.5, size=0.5) + + geom_line(data=podbootdata, + aes(x=s_offset, y=n_pods*inode_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.2) + + geom_point(data=podbootdata, + aes(x=s_offset, y=n_pods*inode_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.3, size=0.5) + + labs(colour="") + + xlab("seconds") + + ylab("inodes free") + + scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./inode_scale, name="pods")) + + ggtitle("inodes free") + + theme(legend.position="bottom") + + theme(axis.text.x=element_text(angle=90)) + + page4 = grid.arrange( + inode_line_plot, + inode_stats_plot, + ncol=1 + ) + + # pagebreak, as the graphs overflow the page otherwise + cat("\n\n\\pagebreak\n") + + ########## Output interface page packets and octets ############## + ip_scale = max(c(max(ifpacketdata$tx, na.rm=TRUE), + max(ifpacketdata$rx, na.rm=TRUE))) / max(podbootdata$n_pods) + interface_packet_line_plot <- ggplot() + + geom_line(data=ifpacketdata, + aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), + group=interaction(testname, node, name, "tx")), + alpha=0.2, na.rm=TRUE) + + geom_point(data=ifpacketdata, + aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), + group=interaction(testname, node, name, "tx")), + alpha=0.5, size=0.5, na.rm=TRUE) + + geom_line(data=ifpacketdata, + aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), + group=interaction(testname, node, name, "rx")), + alpha=0.2, na.rm=TRUE) + + geom_point(data=ifpacketdata, + aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), + group=interaction(testname, node, name, "rx")), + alpha=0.5, size=0.5, na.rm=TRUE) + + geom_line(data=podbootdata, + aes(x=s_offset, y=n_pods*ip_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.2) + + geom_point(data=podbootdata, + aes(x=s_offset, y=n_pods*ip_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.3, size=0.5) + + labs(colour="") + + xlab("seconds") + + ylab("packets") + + scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./ip_scale, name="pods")) + + ggtitle("interface packets") + + theme(legend.position="bottom") + + theme(axis.text.x=element_text(angle=90)) + + oct_scale = max(c(max(ifoctetdata$tx, na.rm=TRUE), + max(ifoctetdata$rx, na.rm=TRUE))) / max(podbootdata$n_pods) + interface_octet_line_plot <- ggplot() + + geom_line(data=ifoctetdata, + aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), + group=interaction(testname, node, name, "tx")), + alpha=0.2, na.rm=TRUE) + + geom_point(data=ifoctetdata, + aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), + group=interaction(testname, node, name, "tx")), + alpha=0.5, size=0.5, na.rm=TRUE) + + geom_line(data=ifoctetdata, + aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), + group=interaction(testname, node, name, "rx")), + alpha=0.2, na.rm=TRUE) + + geom_point(data=ifoctetdata, + aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), + group=interaction(testname, node, name, "rx")), + alpha=0.5, size=0.5, na.rm=TRUE) + + geom_line(data=podbootdata, + aes(x=s_offset, y=n_pods*oct_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.2) + + geom_point(data=podbootdata, + aes(x=s_offset, y=n_pods*oct_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.3, size=0.5) + + labs(colour="") + + xlab("seconds") + + ylab("octets") + + scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./oct_scale, name="pods")) + + ggtitle("interface octets") + + theme(legend.position="bottom") + + theme(axis.text.x=element_text(angle=90)) + + page5 = grid.arrange( + interface_packet_line_plot, + interface_octet_line_plot, + ncol=1 + ) + + # pagebreak, as the graphs overflow the page otherwise + cat("\n\n\\pagebreak\n") + + ########## Output interface page drops and errors ############## + # drops are often 0, so providing 1 so we won't scale by infinity + drop_scale = max(c(1, + max(ifdropdata$tx, na.rm=TRUE), + max(ifdropdata$rx, na.rm=TRUE))) / max(podbootdata$n_pods) + interface_drop_line_plot <- ggplot() + + geom_line(data=ifdropdata, + aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), + group=interaction(testname, node, name, "tx")), + alpha=0.2, na.rm=TRUE) + + geom_point(data=ifdropdata, + aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), + group=interaction(testname, node, name, "tx")), + alpha=0.5, size=0.5, na.rm=TRUE) + + geom_line(data=ifdropdata, + aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), + group=interaction(testname, node, name, "rx")), + alpha=0.2, na.rm=TRUE) + + geom_point(data=ifdropdata, + aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), + group=interaction(testname, node, name, "rx")), + alpha=0.5, size=0.5, na.rm=TRUE) + + geom_line(data=podbootdata, + aes(x=s_offset, y=n_pods*drop_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.2) + + geom_point(data=podbootdata, + aes(x=s_offset, y=n_pods*drop_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.3, size=0.5) + + labs(colour="") + + xlab("seconds") + + ylab("drops") + + scale_y_continuous(breaks=pretty_breaks(), sec.axis=sec_axis(~ ./drop_scale, name="pods", labels=comma)) + + ggtitle("interface drops") + + theme(legend.position="bottom") + + theme(axis.text.x=element_text(angle=90)) + + # errors are often 0, so providing 1 so we won't scale by infinity + error_scale = max(c(1, + max(iferrordata$tx, na.rm=TRUE), + max(iferrordata$rx, na.rm=TRUE))) / max(podbootdata$n_pods) + interface_error_line_plot <- ggplot() + + geom_line(data=iferrordata, + aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), + group=interaction(testname, node, name, name, "tx")), + alpha=0.2, na.rm=TRUE) + + geom_point(data=iferrordata, + aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), + group=interaction(testname, node, name, "tx")), + alpha=0.5, size=0.5, na.rm=TRUE) + + geom_line(data=iferrordata, + aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), + group=interaction(testname, node, name, "rx")), + alpha=0.2, na.rm=TRUE) + + geom_point(data=iferrordata, + aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), + group=interaction(testname, node, name, "rx")), + alpha=0.5, size=0.5, na.rm=TRUE) + + geom_line(data=podbootdata, + aes(x=s_offset, y=n_pods*error_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.2) + + geom_point(data=podbootdata, + aes(x=s_offset, y=n_pods*error_scale, colour=interaction(testname,"pod count"), group=testname), + alpha=0.3, size=0.5) + + labs(colour="") + + xlab("seconds") + + ylab("errors") + + scale_y_continuous(breaks=pretty_breaks(), sec.axis=sec_axis(~ ./error_scale, name="pods", labels=comma)) + + ggtitle("interface errors") + + theme(legend.position="bottom") + + theme(axis.text.x=element_text(angle=90)) + + page6 = grid.arrange( + interface_drop_line_plot, + interface_error_line_plot, + ncol=1 + ) } -# It's nice to show the graphs in Gb, at least for any decent sized test -# run, so make a new column with that pre-divided data in it for us to use. -memfreedata$mem_free_gb = memfreedata$value/(1024*1024*1024) -# And show the boot times in seconds, not ms -podbootdata$launch_time_s = podbootdata$launch_time/1000.0 - - -########### Output memory page ############## -mem_stats_plot = suppressWarnings(ggtexttable(data.frame(memstats), - theme=ttheme(base_size=10), - rows=NULL - )) - -mem_scale = (max(memfreedata$value) / (1024*1024*1024)) / max(podbootdata$n_pods) -mem_line_plot <- ggplot() + - geom_line(data=memfreedata, - aes(s_offset, mem_free_gb, colour=interaction(testname, node), - group=interaction(testname, node)), - alpha=0.3) + - geom_point(data=memfreedata, - aes(s_offset, mem_free_gb, colour=interaction(testname, node), - group=interaction(testname, node)), - alpha=0.5, size=0.5) + - geom_line(data=podbootdata, - aes(x=s_offset, y=n_pods*mem_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.2) + - geom_point(data=podbootdata, - aes(x=s_offset, y=n_pods*mem_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.3, size=0.5) + - labs(colour="") + - xlab("seconds") + - ylab("System Avail (Gb)") + - scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./mem_scale, name="pods")) + - ggtitle("System Memory free") + - theme(legend.position="bottom") + - theme(axis.text.x=element_text(angle=90)) - -page1 = grid.arrange( - mem_line_plot, - mem_stats_plot, - ncol=1 - ) - -# pagebreak, as the graphs overflow the page otherwise -cat("\n\n\\pagebreak\n") - -########## Output cpu page ############## -cpu_stats_plot = suppressWarnings(ggtexttable(data.frame(cpustats), - theme=ttheme(base_size=10), - rows=NULL - )) - -cpu_scale = max(cpuidledata$value) / max(podbootdata$n_pods) -cpu_line_plot <- ggplot() + - geom_line(data=cpuidledata, - aes(x=s_offset, y=value, colour=interaction(testname, node), - group=interaction(testname, node)), - alpha=0.3) + - geom_point(data=cpuidledata, - aes(x=s_offset, y=value, colour=interaction(testname, node), - group=interaction(testname, node)), - alpha=0.5, size=0.5) + - geom_line(data=podbootdata, - aes(x=s_offset, y=n_pods*cpu_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.2) + - geom_point(data=podbootdata, - aes(x=s_offset, y=n_pods*cpu_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.3, size=0.5) + - labs(colour="") + - scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./cpu_scale, name="pods")) + - xlab("seconds") + - ylab("System CPU Idle (%)") + - ggtitle("System CPU usage") + - theme(legend.position="bottom") + - theme(axis.text.x=element_text(angle=90)) - -page2 = grid.arrange( - cpu_line_plot, - cpu_stats_plot, - ncol=1 - ) - -# pagebreak, as the graphs overflow the page otherwise -cat("\n\n\\pagebreak\n") - -########## Output boot page ############## -boot_stats_plot = suppressWarnings(ggtexttable(data.frame(bootstats), - theme=ttheme(base_size=10), - rows=NULL - )) - -boot_line_plot <- ggplot() + - geom_line(data=podbootdata, - aes(n_pods, launch_time_s, colour=testname, group=testname), - alpha=0.2) + - xlab("pods") + - ylab("Boot time (s)") + - ggtitle("Pod boot time") + - theme(legend.position="bottom") + - theme(axis.text.x=element_text(angle=90)) - -page3 = grid.arrange( - boot_line_plot, - boot_stats_plot, - ncol=1 - ) - -# pagebreak, as the graphs overflow the page otherwise -cat("\n\n\\pagebreak\n") - -########## Output inode page ############## -inode_stats_plot = suppressWarnings(ggtexttable(data.frame(inodestats), - theme=ttheme(base_size=10), - rows=NULL - )) - -inode_scale = max(inodefreedata$value) / max(podbootdata$n_pods) -inode_line_plot <- ggplot() + - geom_line(data=inodefreedata, - aes(x=s_offset, y=value, colour=interaction(testname, node), - group=interaction(testname, node)), - alpha=0.2) + - geom_point(data=inodefreedata, - aes(x=s_offset, y=value, colour=interaction(testname, node), - group=interaction(testname, node)), - alpha=0.5, size=0.5) + - geom_line(data=podbootdata, - aes(x=s_offset, y=n_pods*inode_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.2) + - geom_point(data=podbootdata, - aes(x=s_offset, y=n_pods*inode_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.3, size=0.5) + - labs(colour="") + - xlab("seconds") + - ylab("inodes free") + - scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./inode_scale, name="pods")) + - ggtitle("inodes free") + - theme(legend.position="bottom") + - theme(axis.text.x=element_text(angle=90)) - -page4 = grid.arrange( - inode_line_plot, - inode_stats_plot, - ncol=1 - ) - -# pagebreak, as the graphs overflow the page otherwise -cat("\n\n\\pagebreak\n") - -########## Output interface page packets and octets ############## -ip_scale = max(c(max(ifpacketdata$tx, na.rm=TRUE), - max(ifpacketdata$rx, na.rm=TRUE))) / max(podbootdata$n_pods) -interface_packet_line_plot <- ggplot() + - geom_line(data=ifpacketdata, - aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), - group=interaction(testname, node, name, "tx")), - alpha=0.2, na.rm=TRUE) + - geom_point(data=ifpacketdata, - aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), - group=interaction(testname, node, name, "tx")), - alpha=0.5, size=0.5, na.rm=TRUE) + - geom_line(data=ifpacketdata, - aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), - group=interaction(testname, node, name, "rx")), - alpha=0.2, na.rm=TRUE) + - geom_point(data=ifpacketdata, - aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), - group=interaction(testname, node, name, "rx")), - alpha=0.5, size=0.5, na.rm=TRUE) + - geom_line(data=podbootdata, - aes(x=s_offset, y=n_pods*ip_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.2) + - geom_point(data=podbootdata, - aes(x=s_offset, y=n_pods*ip_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.3, size=0.5) + - labs(colour="") + - xlab("seconds") + - ylab("packets") + - scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./ip_scale, name="pods")) + - ggtitle("interface packets") + - theme(legend.position="bottom") + - theme(axis.text.x=element_text(angle=90)) - -oct_scale = max(c(max(ifoctetdata$tx, na.rm=TRUE), - max(ifoctetdata$rx, na.rm=TRUE))) / max(podbootdata$n_pods) -interface_octet_line_plot <- ggplot() + - geom_line(data=ifoctetdata, - aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), - group=interaction(testname, node, name, "tx")), - alpha=0.2, na.rm=TRUE) + - geom_point(data=ifoctetdata, - aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), - group=interaction(testname, node, name, "tx")), - alpha=0.5, size=0.5, na.rm=TRUE) + - geom_line(data=ifoctetdata, - aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), - group=interaction(testname, node, name, "rx")), - alpha=0.2, na.rm=TRUE) + - geom_point(data=ifoctetdata, - aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), - group=interaction(testname, node, name, "rx")), - alpha=0.5, size=0.5, na.rm=TRUE) + - geom_line(data=podbootdata, - aes(x=s_offset, y=n_pods*oct_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.2) + - geom_point(data=podbootdata, - aes(x=s_offset, y=n_pods*oct_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.3, size=0.5) + - labs(colour="") + - xlab("seconds") + - ylab("octets") + - scale_y_continuous(labels=comma, sec.axis=sec_axis(~ ./oct_scale, name="pods")) + - ggtitle("interface octets") + - theme(legend.position="bottom") + - theme(axis.text.x=element_text(angle=90)) - -page5 = grid.arrange( - interface_packet_line_plot, - interface_octet_line_plot, - ncol=1 - ) - -# pagebreak, as the graphs overflow the page otherwise -cat("\n\n\\pagebreak\n") - -########## Output interface page drops and errors ############## -# drops are often 0, so providing 1 so we won't scale by infinity -drop_scale = max(c(1, - max(ifdropdata$tx, na.rm=TRUE), - max(ifdropdata$rx, na.rm=TRUE))) / max(podbootdata$n_pods) -interface_drop_line_plot <- ggplot() + - geom_line(data=ifdropdata, - aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), - group=interaction(testname, node, name, "tx")), - alpha=0.2, na.rm=TRUE) + - geom_point(data=ifdropdata, - aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), - group=interaction(testname, node, name, "tx")), - alpha=0.5, size=0.5, na.rm=TRUE) + - geom_line(data=ifdropdata, - aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), - group=interaction(testname, node, name, "rx")), - alpha=0.2, na.rm=TRUE) + - geom_point(data=ifdropdata, - aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), - group=interaction(testname, node, name, "rx")), - alpha=0.5, size=0.5, na.rm=TRUE) + - geom_line(data=podbootdata, - aes(x=s_offset, y=n_pods*drop_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.2) + - geom_point(data=podbootdata, - aes(x=s_offset, y=n_pods*drop_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.3, size=0.5) + - labs(colour="") + - xlab("seconds") + - ylab("drops") + - scale_y_continuous(breaks=pretty_breaks(), sec.axis=sec_axis(~ ./drop_scale, name="pods", labels=comma)) + - ggtitle("interface drops") + - theme(legend.position="bottom") + - theme(axis.text.x=element_text(angle=90)) - -# errors are often 0, so providing 1 so we won't scale by infinity -error_scale = max(c(1, - max(iferrordata$tx, na.rm=TRUE), - max(iferrordata$rx, na.rm=TRUE))) / max(podbootdata$n_pods) -interface_error_line_plot <- ggplot() + - geom_line(data=iferrordata, - aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), - group=interaction(testname, node, name, name, "tx")), - alpha=0.2, na.rm=TRUE) + - geom_point(data=iferrordata, - aes(x=s_offset, y=tx, colour=interaction(testname, node, name, "tx"), - group=interaction(testname, node, name, "tx")), - alpha=0.5, size=0.5, na.rm=TRUE) + - geom_line(data=iferrordata, - aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), - group=interaction(testname, node, name, "rx")), - alpha=0.2, na.rm=TRUE) + - geom_point(data=iferrordata, - aes(x=s_offset, y=rx, colour=interaction(testname, node, name, "rx"), - group=interaction(testname, node, name, "rx")), - alpha=0.5, size=0.5, na.rm=TRUE) + - geom_line(data=podbootdata, - aes(x=s_offset, y=n_pods*error_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.2) + - geom_point(data=podbootdata, - aes(x=s_offset, y=n_pods*error_scale, colour=interaction(testname,"pod count"), group=testname), - alpha=0.3, size=0.5) + - labs(colour="") + - xlab("seconds") + - ylab("errors") + - scale_y_continuous(breaks=pretty_breaks(), sec.axis=sec_axis(~ ./error_scale, name="pods", labels=comma)) + - ggtitle("interface errors") + - theme(legend.position="bottom") + - theme(axis.text.x=element_text(angle=90)) - -page6 = grid.arrange( - interface_drop_line_plot, - interface_error_line_plot, - ncol=1 - ) +render_collectd_scaling() diff --git a/metrics/report/report_dockerfile/dut-details.R b/metrics/report/report_dockerfile/dut-details.R index 7a707e5..bd4a23a 100755 --- a/metrics/report/report_dockerfile/dut-details.R +++ b/metrics/report/report_dockerfile/dut-details.R @@ -13,95 +13,105 @@ library(gridExtra) # together. suppressMessages(suppressWarnings(library(ggpubr))) # for ggtexttable. suppressMessages(library(jsonlite)) # to load the data. -# A list of all the known results files we might find the information inside. -resultsfiles=c( - "k8s-parallel.json", - "k8s-scaling.json", - "k8s-rapid.json" - ) +render_dut_details <- function() +{ + # A list of all the known results files we might find the information inside. + resultsfiles=c( + "k8s-parallel.json", + "k8s-scaling.json", + "k8s-rapid.json" + ) -data=c() -stats=c() -stats_names=c() + data=c() + stats=c() + stats_names=c() -# For each set of results -for (currentdir in resultdirs) { - count=1 - dirstats=c() - for (resultsfile in resultsfiles) { - fname=paste(inputdir, currentdir, resultsfile, sep="/") - if ( !file.exists(fname)) { - #warning(paste("Skipping non-existent file: ", fname)) - next - } - - # Derive the name from the test result dirname - datasetname=basename(currentdir) - - # Import the data - fdata=fromJSON(fname) - - if (length(fdata$'kubectl-version') != 0 ) { - # We have kata-runtime data - dirstats=tibble("Client Ver"=as.character(fdata$'kubectl-version'$clientVersion$gitVersion)) - dirstats=cbind(dirstats, "Server Ver"=as.character(fdata$'kubectl-version'$serverVersion$gitVersion)) - numnodes= nrow(fdata$'kubectl-get-nodes'$items) - dirstats=cbind(dirstats, "No. nodes"=as.character(numnodes)) - - if (numnodes != 0) { - first_node=fdata$'kubectl-get-nodes'$items[1,] - dirstats=cbind(dirstats, "- Node0 name"=as.character(first_node$metadata$name)) - - havekata=first_node$metadata$labels$'katacontainers.io/kata-runtime' - if ( is.null(havekata) ) { - dirstats=cbind(dirstats, " Have Kata"=as.character('false')) - } else { - dirstats=cbind(dirstats, " Have Kata"=as.character(havekata)) - } - - dirstats=cbind(dirstats, " CPUs"=as.character(first_node$status$capacity$cpu)) - dirstats=cbind(dirstats, " Memory"=as.character(first_node$status$capacity$memory)) - dirstats=cbind(dirstats, " MaxPods"=as.character(first_node$status$capacity$pods)) - dirstats=cbind(dirstats, " PodCIDR"=as.character(first_node$spec$podCIDR)) - - dirstats=cbind(dirstats, " runtime"=as.character(first_node$status$nodeInfo$containerRuntimeVersion)) - dirstats=cbind(dirstats, " kernel"=as.character(first_node$status$nodeInfo$kernelVersion)) - dirstats=cbind(dirstats, " kubeProxy"=as.character(first_node$status$nodeInfo$kubeProxyVersion)) - dirstats=cbind(dirstats, " Kubelet"=as.character(first_node$status$nodeInfo$kubeletVersion)) - dirstats=cbind(dirstats, " OS"=as.character(first_node$status$nodeInfo$osImage)) + # For each set of results + for (currentdir in resultdirs) { + count=1 + dirstats=c() + datasetname=c() + for (resultsfile in resultsfiles) { + fname=paste(inputdir, currentdir, resultsfile, sep="/") + if ( !file.exists(fname)) { + #warning(paste("Skipping non-existent file: ", fname)) + next } - break + # Derive the name from the test result dirname + datasetname=basename(currentdir) + + # Import the data + fdata=fromJSON(fname) + + if (length(fdata$'kubectl-version') != 0 ) { + # We have kata-runtime data + dirstats=tibble("Client Ver"=as.character(fdata$'kubectl-version'$clientVersion$gitVersion)) + dirstats=cbind(dirstats, "Server Ver"=as.character(fdata$'kubectl-version'$serverVersion$gitVersion)) + numnodes= nrow(fdata$'kubectl-get-nodes'$items) + dirstats=cbind(dirstats, "No. nodes"=as.character(numnodes)) + + if (numnodes != 0) { + first_node=fdata$'kubectl-get-nodes'$items[1,] + dirstats=cbind(dirstats, "- Node0 name"=as.character(first_node$metadata$name)) + + havekata=first_node$metadata$labels$'katacontainers.io/kata-runtime' + if ( is.null(havekata) ) { + dirstats=cbind(dirstats, " Have Kata"=as.character('false')) + } else { + dirstats=cbind(dirstats, " Have Kata"=as.character(havekata)) + } + + dirstats=cbind(dirstats, " CPUs"=as.character(first_node$status$capacity$cpu)) + dirstats=cbind(dirstats, " Memory"=as.character(first_node$status$capacity$memory)) + dirstats=cbind(dirstats, " MaxPods"=as.character(first_node$status$capacity$pods)) + dirstats=cbind(dirstats, " PodCIDR"=as.character(first_node$spec$podCIDR)) + + dirstats=cbind(dirstats, " runtime"=as.character(first_node$status$nodeInfo$containerRuntimeVersion)) + dirstats=cbind(dirstats, " kernel"=as.character(first_node$status$nodeInfo$kernelVersion)) + dirstats=cbind(dirstats, " kubeProxy"=as.character(first_node$status$nodeInfo$kubeProxyVersion)) + dirstats=cbind(dirstats, " Kubelet"=as.character(first_node$status$nodeInfo$kubeletVersion)) + dirstats=cbind(dirstats, " OS"=as.character(first_node$status$nodeInfo$osImage)) + } + + break + } } + + if ( length(dirstats) == 0 ) { + cat(paste("No valid data found for directory ", currentdir, "\n\n")) + } + + # use plyr rbind.fill so we can combine disparate version info frames + stats=rbind.fill(stats, dirstats) + stats_names=rbind(stats_names, datasetname) } - if ( length(dirstats) == 0 ) { - warning(paste("No valid data found for directory ", currentdir)) + if ( length(stats_names) == 0 ) { + cat("No system details found\n\n") + return() } - # use plyr rbind.fill so we can combine disparate version info frames - stats=rbind.fill(stats, dirstats) - stats_names=rbind(stats_names, datasetname) + rownames(stats) = stats_names + + # Rotate the tibble so we get data dirs as the columns + spun_stats = as_tibble(cbind(What=names(stats), t(stats))) + + # Build us a text table of numerical results + # Set up as left hand justify, so the node data indent renders. + tablefontsize=8 + tbody.style = tbody_style(hjust=0, x=0.1, size=tablefontsize) + stats_plot = suppressWarnings(ggtexttable(data.frame(spun_stats, check.names=FALSE), + theme=ttheme(base_size=tablefontsize, tbody.style=tbody.style), + rows=NULL + )) + + # It may seem odd doing a grid of 1x1, but it should ensure we get a uniform format and + # layout to match the other charts and tables in the report. + master_plot = grid.arrange( + stats_plot, + nrow=1, + ncol=1 ) } -rownames(stats) = stats_names - -# Rotate the tibble so we get data dirs as the columns -spun_stats = as_tibble(cbind(What=names(stats), t(stats))) - -# Build us a text table of numerical results -# Set up as left hand justify, so the node data indent renders. -tablefontsize=8 -tbody.style = tbody_style(hjust=0, x=0.1, size=tablefontsize) -stats_plot = suppressWarnings(ggtexttable(data.frame(spun_stats, check.names=FALSE), - theme=ttheme(base_size=tablefontsize, tbody.style=tbody.style), - rows=NULL - )) - -# It may seem odd doing a grid of 1x1, but it should ensure we get a uniform format and -# layout to match the other charts and tables in the report. -master_plot = grid.arrange( - stats_plot, - nrow=1, - ncol=1 ) - +render_dut_details() diff --git a/metrics/report/report_dockerfile/elasticsearchr.R b/metrics/report/report_dockerfile/elasticsearchr.R new file mode 100644 index 0000000..9a55e48 --- /dev/null +++ b/metrics/report/report_dockerfile/elasticsearchr.R @@ -0,0 +1,26 @@ + +library('elasticsearchr') + +for_scaling <- query('{ +"bool": { + "must": [ + { "match": + { + "test.testname": "k8s scaling" + } + } + ] +} +}') + +these_fields <- select_fields('{ + "includes": [ + "date.Date", + "k8s-scaling.BootResults.launch_time.Result", + "k8s-scaling.BootResults.n_pods.Result" + ] +}') + +sort_by_date <- sort_on('[{"date.Date": {"order": "asc"}}]') + +x=elastic("http://192.168.0.111:9200", "logtest") %search% (for_scaling + sort_by_date + these_fields) diff --git a/metrics/report/report_dockerfile/metrics_report.Rmd b/metrics/report/report_dockerfile/metrics_report.Rmd index 630365a..e715ad1 100644 --- a/metrics/report/report_dockerfile/metrics_report.Rmd +++ b/metrics/report/report_dockerfile/metrics_report.Rmd @@ -32,7 +32,7 @@ This [test](https://github.com/clearlinux/cloud-native-setup/metrics/scaling/k8s measures the time taken to launch and delete pods in parallel using a deployment. The times are how long it takes for the whole deployment operation to complete. -```{r parallel, echo=FALSE, fig.cap="K8S parallel pods"} +```{r parallel, echo=FALSE, fig.cap="K8S parallel pods", results='asis'} source('parallel.R') ``` @@ -57,7 +57,7 @@ This table describes the test system details, as derived from the information co in the test results files. -```{r dut, echo=FALSE, fig.cap="System configuration details"} +```{r dut, echo=FALSE, fig.cap="System configuration details", results='asis'} source('dut-details.R') ``` @@ -67,6 +67,6 @@ source('dut-details.R') This table describes node details within the Kubernetes cluster that have been used for test. -```{r node, echo=FALSE, fig.cap="Node information within Kubernetes cluster"} +```{r node, echo=FALSE, fig.cap="Node information within Kubernetes cluster", results='asis'} source('node-info.R') ``` diff --git a/metrics/report/report_dockerfile/node-info.R b/metrics/report/report_dockerfile/node-info.R index eeaa9f8..9f98a84 100755 --- a/metrics/report/report_dockerfile/node-info.R +++ b/metrics/report/report_dockerfile/node-info.R @@ -13,83 +13,96 @@ library(gridExtra) # together. suppressMessages(suppressWarnings(library(ggpubr))) # for ggtexttable. suppressMessages(library(jsonlite)) # to load the data. -# A list of all the known results files we might find the information inside. -resultsfiles=c( - "k8s-scaling.json" - ) +render_node_info <- function() +{ + # A list of all the known results files we might find the information inside. + resultsfiles=c( + "k8s-scaling.json" + ) -stats=c() -stats_names=c() -max_char_name_node=18 + stats=c() + stats_names=c() + datasetname=c() + complete_data=c() + max_char_name_node=18 -# list for each dirstats -dirstats_list=list() -j=1 + # list for each dirstats + dirstats_list=list() + j=1 -# For each set of results -for (currentdir in resultdirs) { - dirstats=c() - for (resultsfile in resultsfiles) { - fname=paste(inputdir, currentdir, resultsfile, sep="/") - if ( !file.exists(fname)) { - next - } - - # Derive the name from the test result dirname - datasetname=basename(currentdir) - - # Import the data - fdata=fromJSON(fname) - - if (length(fdata$'kubectl-version') != 0 ) { - numnodes= nrow(fdata$'kubectl-get-nodes'$items) - for (i in 1:numnodes) { - node_i=fdata$'kubectl-get-nodes'$items[i,] - node_info=fdata$'socketsPerNode'[i,] - - # Substring node name so it fits properly into final table - node_name=node_i$metadata$name - if ( nchar(node_name) >= max_char_name_node) { - dirstats=tibble("Node \nname"=as.character(substring(node_name, 1, max_char_name_node))) - } else { - dirstats=tibble("Node \nname"=as.character(node_name)) - } - - dirstats=cbind(dirstats, "CPUs"=as.character(node_i$status$capacity$cpu)) - dirstats=cbind(dirstats, "Memory"=as.character(node_i$status$capacity$memory)) - dirstats=cbind(dirstats, "Max \nPods"=as.character(node_i$status$capacity$pods)) - dirstats=cbind(dirstats, "Count \nsockets"=as.character(node_info$num_sockets)) - dirstats=cbind(dirstats, "Have \nhypervisor"=as.character(node_info$hypervisor)) - - dirstats=cbind(dirstats, "kernel"=as.character(node_i$status$nodeInfo$kernelVersion)) - dirstats=cbind(dirstats, "OS"=as.character(node_i$status$nodeInfo$osImage)) - dirstats=cbind(dirstats, "Test"=as.character(datasetname)) - - dirstats_list[[j]]=dirstats - j=j+1 + # For each set of results + for (currentdir in resultdirs) { + dirstats=c() + for (resultsfile in resultsfiles) { + fname=paste(inputdir, currentdir, resultsfile, sep="/") + if ( !file.exists(fname)) { + next + } + + # Derive the name from the test result dirname + datasetname=basename(currentdir) + + # Import the data + fdata=fromJSON(fname) + + if (length(fdata$'kubectl-version') != 0 ) { + numnodes= nrow(fdata$'kubectl-get-nodes'$items) + for (i in 1:numnodes) { + node_i=fdata$'kubectl-get-nodes'$items[i,] + node_info=fdata$'socketsPerNode'[i,] + + # Substring node name so it fits properly into final table + node_name=node_i$metadata$name + if ( nchar(node_name) >= max_char_name_node) { + dirstats=tibble("Node \nname"=as.character(substring(node_name, 1, max_char_name_node))) + } else { + dirstats=tibble("Node \nname"=as.character(node_name)) + } + + dirstats=cbind(dirstats, "CPUs"=as.character(node_i$status$capacity$cpu)) + dirstats=cbind(dirstats, "Memory"=as.character(node_i$status$capacity$memory)) + dirstats=cbind(dirstats, "Max \nPods"=as.character(node_i$status$capacity$pods)) + dirstats=cbind(dirstats, "Count \nsockets"=as.character(node_info$num_sockets)) + dirstats=cbind(dirstats, "Have \nhypervisor"=as.character(node_info$hypervisor)) + + dirstats=cbind(dirstats, "kernel"=as.character(node_i$status$nodeInfo$kernelVersion)) + dirstats=cbind(dirstats, "OS"=as.character(node_i$status$nodeInfo$osImage)) + dirstats=cbind(dirstats, "Test"=as.character(datasetname)) + + dirstats_list[[j]]=dirstats + j=j+1 + } + complete_data = do.call(rbind, dirstats_list) } - complete_data = do.call(rbind, dirstats_list) } + + if ( length(complete_data) == 0 ) { + cat(paste("No valid data found for directory ", currentdir, "\n\n")) + } + + # use plyr rbind.fill so we can combine disparate version info frames + stats=rbind.fill(stats, complete_data) + stats_names=rbind(stats_names, datasetname) } - if ( length(complete_data) == 0 ) { - warning(paste("No valid data found for directory ", currentdir)) + if ( length(stats_names) == 0 ) { + cat("No node stats found\n\n"); + return() } - # use plyr rbind.fill so we can combine disparate version info frames - stats=rbind.fill(stats, complete_data) - stats_names=rbind(stats_names, datasetname) + # Build us a text table of numerical results + # Set up as left hand justify, so the node data indent renders. + tablefontsize=8 + tbody.style = tbody_style(hjust=0, x=0.1, size=tablefontsize) + stats_plot = suppressWarnings(ggtexttable(data.frame(complete_data, check.names=FALSE), + theme=ttheme(base_size=tablefontsize, tbody.style=tbody.style), + rows=NULL)) + + # It may seem odd doing a grid of 1x1, but it should ensure we get a uniform format and + # layout to match the other charts and tables in the report. + master_plot = grid.arrange(stats_plot, + nrow=1, + ncol=1 ) } -# Build us a text table of numerical results -# Set up as left hand justify, so the node data indent renders. -tablefontsize=8 -tbody.style = tbody_style(hjust=0, x=0.1, size=tablefontsize) -stats_plot = suppressWarnings(ggtexttable(data.frame(complete_data, check.names=FALSE), - theme=ttheme(base_size=tablefontsize, tbody.style=tbody.style), - rows=NULL)) -# It may seem odd doing a grid of 1x1, but it should ensure we get a uniform format and -# layout to match the other charts and tables in the report. -master_plot = grid.arrange(stats_plot, - nrow=1, - ncol=1 ) +render_node_info() diff --git a/metrics/report/report_dockerfile/parallel.R b/metrics/report/report_dockerfile/parallel.R index 7a778d9..a6d03ba 100755 --- a/metrics/report/report_dockerfile/parallel.R +++ b/metrics/report/report_dockerfile/parallel.R @@ -13,113 +13,123 @@ suppressMessages(suppressWarnings(library(ggpubr))) # for ggtexttable. suppressMessages(library(jsonlite)) # to load the data. suppressMessages(library(scales)) # For de-science notation of axis -testnames=c( - "k8s-parallel*" -) +render_parallel <- function() +{ + testnames=c( + "k8s-parallel*" + ) -data=c() -stats=c() -rstats=c() -rstats_names=c() -cstats=c() -cstats_names=c() + data=c() + stats=c() + rstats=c() + rstats_names=c() + cstats=c() + cstats_names=c() -skip_points_enable_smooth=0 # Should we draw the points as well as lines on the graphs. + skip_points_enable_smooth=0 # Should we draw the points as well as lines on the graphs. -for (currentdir in resultdirs) { - dirstats=c() - for (testname in testnames) { - matchdir=paste(inputdir, currentdir, sep="") - matchfile=paste(testname, '\\.json', sep="") - files=list.files(matchdir, pattern=matchfile) - if ( length(files) == 0 ) { - #warning(paste("Pattern [", matchdir, "/", matchfile, "] matched nothing")) - } - for (ffound in files) { - fname=paste(inputdir, currentdir, ffound, sep="") - if ( !file.exists(fname)) { - warning(paste("Skipping non-existent file: ", fname)) - next + for (currentdir in resultdirs) { + dirstats=c() + for (testname in testnames) { + matchdir=paste(inputdir, currentdir, sep="") + matchfile=paste(testname, '\\.json', sep="") + files=list.files(matchdir, pattern=matchfile) + if ( length(files) == 0 ) { + #warning(paste("Pattern [", matchdir, "/", matchfile, "] matched nothing")) } + for (ffound in files) { + fname=paste(inputdir, currentdir, ffound, sep="") + if ( !file.exists(fname)) { + warning(paste("Skipping non-existent file: ", fname)) + next + } - # Derive the name from the test result dirname - datasetname=basename(currentdir) + # Derive the name from the test result dirname + datasetname=basename(currentdir) - # Import the data - fdata=fromJSON(fname) - # De-nest the test name specific data - shortname=substr(ffound, 1, nchar(ffound)-nchar(".json")) - fdata=fdata[[shortname]] + # Import the data + fdata=fromJSON(fname) + # De-nest the test name specific data + shortname=substr(ffound, 1, nchar(ffound)-nchar(".json")) + fdata=fdata[[shortname]] - testname=datasetname + testname=datasetname - # convert ms to seconds - cdata=data.frame(boot_time=as.numeric(fdata$BootResults$launch_time$Result)/1000) - cdata=cbind(cdata, delete_time=as.numeric(fdata$BootResults$delete_time$Result)/1000) - cdata=cbind(cdata, npod=as.numeric(fdata$BootResults$n_pods$Result)) + # convert ms to seconds + cdata=data.frame(boot_time=as.numeric(fdata$BootResults$launch_time$Result)/1000) + cdata=cbind(cdata, delete_time=as.numeric(fdata$BootResults$delete_time$Result)/1000) + cdata=cbind(cdata, npod=as.numeric(fdata$BootResults$n_pods$Result)) - # If we have more than 20 items to draw, then do not draw the points on - # the graphs, as they are then too noisy to read. - # But, do draw the smoothed lines to help read the now dense and potentially - # noisy graphs. - if (length(cdata[, "boot_time"]) > 20) { - skip_points_enable_smooth=1 + # If we have more than 20 items to draw, then do not draw the points on + # the graphs, as they are then too noisy to read. + # But, do draw the smoothed lines to help read the now dense and potentially + # noisy graphs. + if (length(cdata[, "boot_time"]) > 20) { + skip_points_enable_smooth=1 + } + + cdata=cbind(cdata, testname=rep(testname, length(cdata[, "boot_time"]) )) + cdata=cbind(cdata, dataset=rep(datasetname, length(cdata[, "boot_time"]) )) + + # Store away as a single set + data=rbind(data, cdata) } - - cdata=cbind(cdata, testname=rep(testname, length(cdata[, "boot_time"]) )) - cdata=cbind(cdata, dataset=rep(datasetname, length(cdata[, "boot_time"]) )) - - # Store away as a single set - data=rbind(data, cdata) } } + + # If we found nothing to process, quit early and nicely + if ( length(data) == 0 ) { + cat("No results files found for parallel tests\n\n") + return() + } + + # Show how boot time changed + boot_line_plot <- ggplot( data=data, aes(npod, boot_time, colour=testname, group=dataset)) + + geom_line( alpha=0.2) + + xlab("parallel pods") + + ylab("Boot time (s)") + + ggtitle("Deployment boot time (detail)") + + #ylim(0, NA) + # For big machines, better to not 0-index + theme(axis.text.x=element_text(angle=90)) + + if ( skip_points_enable_smooth == 0 ) { + boot_line_plot = boot_line_plot + geom_point(alpha=0.3) + } else { + boot_line_plot = bool_line_plot + geom_smooth(se=FALSE, method="loess", size=0.3) + } + + # And get a zero Y index plot. + boot_line_plot_zero = boot_line_plot + ylim(0, NA) + + ggtitle("Deployment boot time (0 index)") + + # Show how boot time changed + delete_line_plot <- ggplot( data=data, aes(npod, delete_time, colour=testname, group=dataset)) + + geom_line(alpha=0.2) + + xlab("parallel pods") + + ylab("Delete time (s)") + + ggtitle("Deployment deletion time (detail)") + + #ylim(0, NA) + # For big machines, better to not 0-index + theme(axis.text.x=element_text(angle=90)) + + if ( skip_points_enable_smooth == 0 ) { + delete_line_plot = delete_line_plot + geom_point(alpha=0.3) + } else { + delete_line_plot = delete_line_plot + geom_smooth(se=FALSE, method="loess", size=0.3) + } + + # And get a 0 indexed Y axis plot + delete_line_plot_zero = delete_line_plot + ylim(0, NA) + + ggtitle("Deployment deletion time (0 index)") + + # See https://www.r-bloggers.com/ggplot2-easy-way-to-mix-multiple-graphs-on-the-same-page/ for + # excellent examples + master_plot = grid.arrange( + boot_line_plot_zero, + delete_line_plot_zero, + boot_line_plot, + delete_line_plot, + nrow=2, + ncol=2 ) } -# Show how boot time changed -boot_line_plot <- ggplot( data=data, aes(npod, boot_time, colour=testname, group=dataset)) + - geom_line( alpha=0.2) + - xlab("parallel pods") + - ylab("Boot time (s)") + - ggtitle("Deployment boot time (detail)") + - #ylim(0, NA) + # For big machines, better to not 0-index - theme(axis.text.x=element_text(angle=90)) - - if ( skip_points_enable_smooth == 0 ) { - boot_line_plot = boot_line_plot + geom_point(alpha=0.3) - } else { - boot_line_plot = bool_line_plot + geom_smooth(se=FALSE, method="loess", size=0.3) - } - - # And get a zero Y index plot. - boot_line_plot_zero = boot_line_plot + ylim(0, NA) + - ggtitle("Deployment boot time (0 index)") - -# Show how boot time changed -delete_line_plot <- ggplot( data=data, aes(npod, delete_time, colour=testname, group=dataset)) + - geom_line(alpha=0.2) + - xlab("parallel pods") + - ylab("Delete time (s)") + - ggtitle("Deployment deletion time (detail)") + - #ylim(0, NA) + # For big machines, better to not 0-index - theme(axis.text.x=element_text(angle=90)) - - if ( skip_points_enable_smooth == 0 ) { - delete_line_plot = delete_line_plot + geom_point(alpha=0.3) - } else { - delete_line_plot = delete_line_plot + geom_smooth(se=FALSE, method="loess", size=0.3) - } - - # And get a 0 indexed Y axis plot - delete_line_plot_zero = delete_line_plot + ylim(0, NA) + - ggtitle("Deployment deletion time (0 index)") - -# See https://www.r-bloggers.com/ggplot2-easy-way-to-mix-multiple-graphs-on-the-same-page/ for -# excellent examples -master_plot = grid.arrange( - boot_line_plot_zero, - delete_line_plot_zero, - boot_line_plot, - delete_line_plot, - nrow=2, - ncol=2 ) - +render_parallel() diff --git a/metrics/report/report_dockerfile/test.R b/metrics/report/report_dockerfile/test.R new file mode 100644 index 0000000..8c9dabe --- /dev/null +++ b/metrics/report/report_dockerfile/test.R @@ -0,0 +1,9 @@ + +suppressMessages(library(jsonlite)) # to load the data. + +options(digits=22) + +x=fromJSON('{"ns": 1567002188374607769}') + +print(x) +print(fromJSON('{"ns": 1567002188374607769}'), digits=22) diff --git a/metrics/report/report_dockerfile/tidy_scaling.R b/metrics/report/report_dockerfile/tidy_scaling.R index ff5dbc2..6a4157e 100755 --- a/metrics/report/report_dockerfile/tidy_scaling.R +++ b/metrics/report/report_dockerfile/tidy_scaling.R @@ -205,7 +205,7 @@ render_tidy_scaling <- function() # Check if we got any stats at all by checking the memstats data. If we found no data, # abort early and nicely if ( length(memstats) == 0 ) { - cat("No results files found for scaling tests\n") + cat("No results files found for scaling tests\n\n") return() }