### ### Draw graph showing relationship between network bandwidth and ### performance, by treating the system as a market for throughput. ### ### See related blog post for the details: ### http://www.lightbluetouchpaper.org/2007/07/18/economics-of-tor-performance/ ### ### Steven J. Murdoch , 2007-07-18 ### ### ### Function declarations ### ### Plot and annotate a point at the intersection of two curves plotIntersect <- function(x, y1=NULL, y2=NULL, i=NULL, ann=NULL, adj=NULL) { if (is.null(i)) iIntersect <- which.min(abs(y1-y2)) else iIntersect <- i points(x[iIntersect], y1[iIntersect], pch=20, col="darkred") if (!is.null(ann)) text(x[iIntersect], y1[iIntersect], ann, adj=adj) return(iIntersect) } ### ### Customization ### ## Number of Tor users (vague estimate) uUsersTotal <- 1e5 ## Bandwidth (bits/sec) of the Tor network (from ## http://www.noreply.org/tor-running-routers/) as of July 2007 rBandwidthTotal <- ( 120 # 120 MByte/sec * 1e6 # convert to byte/sec * 8 ) # convert to bit/sec ## Range for plotting number of users rgUsers <- c(uUsersTotal* 0.4, uUsersTotal * 1.6) ## Number of points to plot on X axis cUserPoints <- 300 ### ### Generate curves ### ## Number of users uUsers <- seq(rgUsers[1], rgUsers[2], length.out=cUserPoints) ## Supply curve: (bandwidth per user) * (number of users) = rBandwidthTotal rSupply <- rBandwidthTotal / uUsers ## Supply curve, for a 50% increase in total bandwidth rBandwidthTotalNew <- rBandwidthTotal * 1.5 rSupplyNew <- rBandwidthTotalNew / uUsers ## Demand curve (arbitrary values, just something that looks OK) rDemandB <- 5e-12*(uUsers^3) + 6000 ## Second demand curve rDemandC <-25*(uUsers-20000)^0.5 ## Find intersect between rDemandB and rSupply iIntersectOrig <- which.min(abs(rSupply-rDemandB)) ## Find how much rDemandC needs to be shifted to intersect at same point rDiff <- rSupply[iIntersectOrig] - rDemandC[iIntersectOrig] ## Shift curve rDemandC <- rDemandC + rDiff ## Find user count at intersection uIntersectOrig <- uUsers[iIntersectOrig] ### ### Plotting ### ## Color declarations (selected from colour-blind-safe pallete) colDemand <- "#336600" colSupply <- "#9900CC" ## Open output file (increase size, so it can be scaled down later and ## anti-aliased) RequestedSize <- Sys.getenv("IMAGESIZE") if (RequestedSize=="") { ImageSize <- c(440, 290) } else { ImageSize <- as.numeric(strsplit(RequestedSize, split="x")[[1]]) } ScaleFactor <- 2 ImageSize <- ImageSize * ScaleFactor png("equilibrium-big.png", width=ImageSize[1], height=ImageSize[2], pointsize=10 * ScaleFactor) ## Style declarations par(mar=c(2.2,2.2,0.1,0.1)) par(lwd=3) par(col="black") ## Define plotting area and plot supply curve plot(uUsers, rSupply, ann=FALSE, frame.plot=FALSE, type="l", col=colSupply, axes=FALSE) title(xlab = "Number of users", line=1) title(ylab = "Throughput per user", line=1) ## Draw other curves lines(uUsers, rSupplyNew, col=colSupply) lines(uUsers, rDemandB, col=colDemand) lines(uUsers, rDemandC, col=colDemand) lines(rep(uIntersectOrig, 2), c(6376.615, 24055.385), col=colDemand) ## Plot and annotate intersection iIntersectA <- plotIntersect(uUsers, rSupplyNew, i=iIntersectOrig, ann="A", adj=c(-1.2,0.1)) iIntersectB <- plotIntersect(uUsers, rSupplyNew, y2=rDemandB, ann="B", adj=c(-2,0.3)) iIntersectC <- plotIntersect(uUsers, rSupplyNew, y2=rDemandC, ann="C", adj=c(0.5,1.8)) ## Arrow showing movement of supply curve arrows(60023.34, 17409.23, 73314.21, 18406.15, lwd=1) ## Hide values (since they are basically guesswork and not important anyway) axis(1, par("usr")[1:2], label=FALSE) axis(2, par("usr")[3:4], label=FALSE) ## Labels text(41634.54, 23942.4, "Supply", adj=c(-0.1,0.5)) text(137844.4, 18810.24, "Demand", adj=c(-0.2,0.5)) ## Save output file dev.off() ### ### Collect some stats ### ## Original values uOrig <- uUsers[iIntersectOrig] rOrig <- rSupply[iIntersectOrig] print(sprintf("Original users: %.0f, bandwidth %.0f", uOrig, rOrig)) ## Percentage change print(sprintf("Intersect A users: %.0f%%, bandwidth %.0f%%", uUsers[iIntersectA]/uOrig*100, rSupplyNew[iIntersectA]/rOrig*100)) print(sprintf("Intersect B users: %.0f%%, bandwidth %.0f%%", uUsers[iIntersectB]/uOrig*100, rSupplyNew[iIntersectB]/rOrig*100)) print(sprintf("Intersect C users: %.0f%%, bandwidth %.0f%%", uUsers[iIntersectC]/uOrig*100, rSupplyNew[iIntersectC]/rOrig*100)) ### ### Old intersection was 94180 users, 10193 bps each ### Intersection A (constant demand) is 100% of old users, and 150% of bandwidth ### Intersection B is 118% of old users and 127% of bandwidth ### Intersection C is 133% of old users and 113% of bandwidth ###