| 1 | #!/usr/bin/env Rscript
 | 
| 2 | #
 | 
| 3 | # release-history.R
 | 
| 4 | 
 | 
| 5 | library(dplyr)
 | 
| 6 | library(ggplot2)
 | 
| 7 | library(tidyr)
 | 
| 8 | 
 | 
| 9 | options(stringsAsFactors = F)
 | 
| 10 | 
 | 
| 11 | Log = function(fmt, ...) {
 | 
| 12 |   cat(sprintf(fmt, ...))
 | 
| 13 |   cat('\n')
 | 
| 14 | }
 | 
| 15 | 
 | 
| 16 | LoadAll = function(in_dir, ctx) {
 | 
| 17 |   wwz = read.delim(file.path(in_dir, 'wwz.tsv'))
 | 
| 18 |   Log('wwz.tsv')
 | 
| 19 |   print(summary(wwz))
 | 
| 20 |   Log('')
 | 
| 21 | 
 | 
| 22 |   wwz$date = as.POSIXct(wwz$date)
 | 
| 23 | 
 | 
| 24 |   wwz %>% arrange(date) -> wwz
 | 
| 25 |   earliest = wwz$date[1]
 | 
| 26 |   latest = wwz$date[nrow(wwz)]
 | 
| 27 |   duration = latest - earliest
 | 
| 28 | 
 | 
| 29 |   Log('Summary: %d releases over %.1f days (%.1f years)', nrow(wwz), duration,
 | 
| 30 |       duration / 365)
 | 
| 31 |   Log('Average interval: %.1f days ', duration / nrow(wwz))
 | 
| 32 | 
 | 
| 33 |   n1 = nrow(wwz %>% filter(spec_wwz != '-'))
 | 
| 34 |   Log('Number of spec.wwz: %d', n1)
 | 
| 35 | 
 | 
| 36 |   n2 = nrow(wwz %>% filter(survey_path != '-'))
 | 
| 37 |   Log('Number of survey_path: %d', n2)
 | 
| 38 | 
 | 
| 39 |   n3 = nrow(wwz %>% filter(cpp_summary_path != '-'))
 | 
| 40 |   Log('Number of cpp_summary_path: %d', n3)
 | 
| 41 | 
 | 
| 42 |   ctx$wwz = wwz
 | 
| 43 | 
 | 
| 44 |   Log('----')
 | 
| 45 |   Log('spec.tsv')
 | 
| 46 |   spec = read.delim(file.path(in_dir, 'spec.tsv'))
 | 
| 47 |   print(summary(spec))
 | 
| 48 |   Log('')
 | 
| 49 | 
 | 
| 50 |   spec$date = as.POSIXct(spec$release_date)
 | 
| 51 | 
 | 
| 52 |   Log('spec rows: %d', nrow(spec))
 | 
| 53 | 
 | 
| 54 |   n1 = nrow(spec %>% filter(!is.na(osh_py_passing)))
 | 
| 55 |   Log('Number of osh_py_passing: %d', n1)
 | 
| 56 | 
 | 
| 57 |   n2 = nrow(spec %>% filter(!is.na(osh_cc_passing)))
 | 
| 58 |   Log('Number of osh_cc_passing: %d', n2)
 | 
| 59 | 
 | 
| 60 | 
 | 
| 61 |   # Version errata:
 | 
| 62 |   #
 | 
| 63 |   # - 0.7.pre4 -- oil-* spec tests were somehow counted here, seems a bit buggy
 | 
| 64 |   #   Delete it because it breaks the monotonicity of the graph
 | 
| 65 |   # - 0.9.1 had stale benchmarks, but spec tests seem OK
 | 
| 66 | 
 | 
| 67 |   Log("Removing bad value in 0.7.pre4")
 | 
| 68 |   spec[spec$version == "0.7.pre4", 'osh_py_passing'] = NA
 | 
| 69 | 
 | 
| 70 |   ctx$spec = spec
 | 
| 71 | 
 | 
| 72 | }
 | 
| 73 | 
 | 
| 74 | ProcessAll = function(ctx) {
 | 
| 75 | 
 | 
| 76 |   long = gather(ctx$spec, implementation, num_passing, c('osh_py_passing', 'osh_cc_passing'))
 | 
| 77 | 
 | 
| 78 |   print(head(long))
 | 
| 79 | 
 | 
| 80 |   blueIndexLeft = which(long$version == '0.2.0' & long$implementation == 'osh_py_passing')
 | 
| 81 |   redIndexLeft = which(long$version == '0.8.pre5' & long$implementation == 'osh_cc_passing')
 | 
| 82 |   #indexRight = which(long$version == '0.9.9')
 | 
| 83 | 
 | 
| 84 |   Log('blueIndexLeft %d', blueIndexLeft)
 | 
| 85 |   Log('redIndexLeft %d', redIndexLeft)
 | 
| 86 |   #Log('indexRight %d', indexRight)
 | 
| 87 | 
 | 
| 88 |   long$label = NA
 | 
| 89 | 
 | 
| 90 |   # Label for readability
 | 
| 91 |   long$label[blueIndexLeft] = sprintf(
 | 
| 92 |     "v%s on %s\npassed %d tests in Python", long$version[blueIndexLeft],
 | 
| 93 |     strftime(long$date[blueIndexLeft], format = '%Y-%m-%d'),
 | 
| 94 |     long$num_passing[blueIndexLeft])
 | 
| 95 | 
 | 
| 96 |   long$label[redIndexLeft] = sprintf(
 | 
| 97 |     "v%s on %s\npassed %d tests in C++", long$version[redIndexLeft],
 | 
| 98 |     strftime(long$date[redIndexLeft], format = '%Y-%m-%d'),
 | 
| 99 |     long$num_passing[redIndexLeft])
 | 
| 100 | 
 | 
| 101 |   print(head(long))
 | 
| 102 |   ctx$long = long  # debugging
 | 
| 103 | 
 | 
| 104 |   g = ggplot(long, aes(date, num_passing, group = implementation,
 | 
| 105 |                        color = implementation)) + 
 | 
| 106 |     xlab('release date') +
 | 
| 107 |     ylab('number of passing spec tests') +
 | 
| 108 |     # Start from 0 spec tests
 | 
| 109 |     ylim(0, NA) +
 | 
| 110 |     theme(legend.position = 'bottom') +
 | 
| 111 |     # lower luminance to make it darker
 | 
| 112 |     scale_color_hue(labels = c('Fast Generated C++', 'Python Source (executable spec)'), l = 40) +
 | 
| 113 |     ggtitle('Middle-Out Progress on https://oilshell.org',
 | 
| 114 |             subtitle = "Weissman score: 99") +
 | 
| 115 |     geom_line() +
 | 
| 116 |     geom_point()
 | 
| 117 | 
 | 
| 118 |   g = g + geom_text(aes(label = label),
 | 
| 119 |                     vjust = 2, hjust = 'inward', size = 5)
 | 
| 120 | 
 | 
| 121 |   # Fallow Period
 | 
| 122 |   g = g + annotate("rect",
 | 
| 123 |                    xmin = as.POSIXct('2020-08-01'),
 | 
| 124 |                    xmax = as.POSIXct('2021-07-01'),
 | 
| 125 |                    ymin = 600,
 | 
| 126 |                    ymax = 1200,
 | 
| 127 |                    alpha = 0.2)
 | 
| 128 | 
 | 
| 129 |   ctx$plot = g
 | 
| 130 | 
 | 
| 131 |   g
 | 
| 132 | }
 | 
| 133 | 
 | 
| 134 | WriteAll = function(ctx, out_dir) {
 | 
| 135 |   png_path = file.path(out_dir, 'spec-test-history-2.png')
 | 
| 136 | 
 | 
| 137 |   png(png_path, width=700, height=600)
 | 
| 138 |   print(ctx$plot)
 | 
| 139 |   dev.off()
 | 
| 140 |   Log('Wrote %s', png_path)
 | 
| 141 | }
 | 
| 142 | 
 | 
| 143 | main = function(argv) {
 | 
| 144 |   in_dir = argv[[1]]
 | 
| 145 |   out_dir = argv[[2]]
 | 
| 146 | 
 | 
| 147 |   ctx = new.env()
 | 
| 148 | 
 | 
| 149 |   LoadAll(in_dir, ctx)
 | 
| 150 |   ProcessAll(ctx)
 | 
| 151 |   WriteAll(ctx, out_dir)
 | 
| 152 | 
 | 
| 153 |   Log('PID %d done', Sys.getpid())
 | 
| 154 | }
 | 
| 155 | 
 | 
| 156 | if (length(sys.frames()) == 0) {
 | 
| 157 |   # increase ggplot font size globally
 | 
| 158 |   theme_set(theme_grey(base_size = 20))
 | 
| 159 | 
 | 
| 160 |   main(commandArgs(TRUE))
 | 
| 161 | }
 |