├── README.md ├── coffee ├── .gitignore ├── burn.go ├── generate.sh ├── README.md ├── jitter.csv ├── finelocking.csv ├── multi.csv ├── perf.go ├── overload.csv ├── varycpu.csv └── main.go └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # dotgo -------------------------------------------------------------------------------- /coffee/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | trace.out 3 | coffee 4 | -------------------------------------------------------------------------------- /coffee/burn.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "hash/adler32" 5 | "log" 6 | "time" 7 | ) 8 | 9 | // opsPerSec is the baseline for useCPU. 10 | // If zero, it is set automatically during init with a 1-second measurement. 11 | // Set to non-zero to skip that initialization. 12 | // Known values: 13 | // - Sameer's Linux workstation: 54000 14 | var opsPerSec int = 54000 15 | 16 | func oneOp() { 17 | var b [64]byte 18 | for j := 0; j < 500; j++ { 19 | b[0] += byte(adler32.Checksum(b[:])) 20 | } 21 | } 22 | 23 | func init() { 24 | if opsPerSec != 0 { 25 | return // already set 26 | } 27 | var d time.Duration 28 | var ops int 29 | for { 30 | start := time.Now() 31 | oneOp() 32 | d += time.Since(start) 33 | ops++ 34 | if d > 1*time.Second { 35 | opsPerSec = ops 36 | log.Print("opsPerSec = ", opsPerSec) 37 | return 38 | } 39 | } 40 | } 41 | 42 | // useCPU uses specified cpu-seconds. 43 | func useCPU(d time.Duration) { 44 | c := opsPerSec * int(d) / int(time.Second) 45 | for i := 0; i < c; i++ { 46 | oneOp() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /coffee/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | echo vary CPU 4 | 5 | truncate -s 0 varycpu.csv 6 | foreach i ( 0 1 2 3 4 5 ) 7 | taskset -c 0-$i go run *.go --header=false --par=0 --dur=10s --mode=ideal,locking,finelocking,parsteam,americano,espresso,linearpipe-0,linearpipe-1,linearpipe-10,splitpipe-0,splitpipe-1,americanopipe-0,americanopipe-1,espressopipe-0,espressopipe-1,multi-1,multi-2,multi-4,multipipe-1,multipipe-2,multipipe-4 2> /dev/null >> varycpu.csv 8 | end 9 | 10 | echo overload 11 | 12 | taskset -c 0-5 go run *.go --par=10,100,1000,10000 --dur=10s --mode=ideal,locking,finelocking,parsteam,americano,espresso,linearpipe-0,linearpipe-1,linearpipe-10,splitpipe-0,splitpipe-1,americanopipe-0,americanopipe-1,espressopipe-0,espressopipe-1,multi-1,multi-2,multi-4,multipipe-1,multipipe-2,multipipe-4 2> /dev/null > overload.csv 13 | 14 | echo multi 15 | 16 | taskset -c 0-5 go run *.go --par=10,100,1000,10000 --dur=10s --mode=multi-1,multi-2,multi-3,multi-4,multi-5,multi-6,multi-7,multi-8,multi-9,multi-10 2> /dev/null > multi.csv 17 | 18 | echo jitter 19 | 20 | truncate -s 0 jitter.csv 21 | foreach j ( 500us 1000us 1500us 2000us ) 22 | taskset -c 0-5 go run *.go --header=false --par=0 --jitter=$j --dur=10s --mode=ideal,locking,finelocking,linearpipe-0,linearpipe-1,linearpipe-10,linearpipe-100 2> /dev/null >> jitter.csv 23 | end 24 | 25 | echo done 26 | -------------------------------------------------------------------------------- /coffee/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The `coffee` program is a tool for studying parallelism, contention, 4 | utilization, latency, and throughput. It simulates making coffee with 5 | a set of machines (grinder for beans, espresso maker, steamer for 6 | milk) and measures the performance of various implementations. The 7 | measurements show the effects of various structural changes and 8 | optimizations. 9 | 10 | Run `coffee` with no arguments to simulate the "ideal" scenario with 1 11 | worker. Run `coffee --help` to see flags for configuring the 12 | simulation. See `generate.sh` for commands that generate measurements 13 | for many different scenarios. 14 | 15 | # Notes 16 | 17 | Run `generate.sh` to regenerate `*.csv` files. 18 | 19 | Use `taskset -c 0-5 go run *.go` to restrict execution to specified CPU IDs. 20 | 21 | Use https://github.com/aclements/perflock to prevent multiple benchmarks from 22 | running at once and keep CPU from running too hot (and so triggering CPU 23 | throttling). 24 | 25 | # Generate torch graphs 26 | 27 | ```shell 28 | foreach mode ( \ 29 | ideal locking finelocking parsteam americano espresso \ 30 | multi-1 multi-2 multi-4 multi-8 \ 31 | linearpipe-0 linearpipe-1 linearpipe-10 \ 32 | splitpipe-0 splitpipe-1 splitpipe-10 \ 33 | multipipe-1 multipipe-2 multipipe-4 multipipe-8 \ 34 | ) 35 | taskset -c 0-5 go run *.go --dur=3s --par=0 --trace=./trace-$mode.out -mode=$mode 36 | go tool trace --pprof=sync ./trace-$mode.out > ./sync-$mode.pprof 37 | go-torch -b ./sync-$mode.pprof -f ./torch-$mode.svg 38 | end 39 | ``` 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /coffee/jitter.csv: -------------------------------------------------------------------------------- 1 | ideal,6,6,0,10s,0s,15315,0,1531,0,10.004169988s,59.452s,594%,99%,3.157,3.464,3.697,3.875,4.056,4.221,4.326,4.550,7.374,500µs 2 | locking,6,6,0,10s,0s,2502,0,250,0,10.021261673s,10.104s,101%,17%,3.472,22.315,23.212,23.747,24.297,25.024,26.870,32.829,44.794,500µs 3 | finelocking,6,6,0,10s,0s,9523,0,952,0,10.005984361s,37.872s,378%,63%,3.262,5.576,6.027,6.298,6.577,6.857,7.093,7.771,10.045,500µs 4 | linearpipe-0,6,6,0,10s,0s,8789,0,878,0,10.005585481s,35.388s,354%,59%,3.776,6.244,6.569,6.802,7.040,7.276,7.425,7.976,12.085,500µs 5 | linearpipe-1,6,6,0,10s,0s,9943,0,994,0,10.005581964s,39.448s,394%,66%,3.677,5.412,5.762,6.028,6.288,6.532,6.687,6.982,9.552,500µs 6 | linearpipe-10,6,6,0,10s,0s,10010,0,1000,0,10.005771661s,39.58s,396%,66%,4.005,5.390,5.730,5.983,6.239,6.474,6.631,6.948,9.941,500µs 7 | linearpipe-100,6,6,0,10s,0s,10000,0,999,0,10.005940092s,39.612s,396%,66%,3.687,5.391,5.730,5.982,6.246,6.494,6.658,6.964,9.172,500µs 8 | ideal,6,6,0,10s,0s,15241,0,1523,0,10.004626061s,59.36s,593%,99%,2.466,3.083,3.540,3.876,4.231,4.544,4.725,5.113,14.553,1ms 9 | locking,6,6,0,10s,0s,2552,0,255,0,10.024009308s,10.096s,101%,17%,3.823,20.858,22.104,23.088,24.345,25.865,27.776,34.329,43.706,1ms 10 | finelocking,6,6,0,10s,0s,8984,0,898,0,10.005338258s,36.18s,362%,60%,3.130,5.127,6.014,6.598,7.239,7.915,8.444,9.911,17.909,1ms 11 | linearpipe-0,6,6,0,10s,0s,7799,0,779,0,10.007270509s,31.604s,316%,53%,4.327,6.480,7.113,7.595,8.110,8.714,9.186,11.055,14.833,1ms 12 | linearpipe-1,6,6,0,10s,0s,9323,0,932,0,10.005960557s,37.312s,373%,62%,3.707,5.296,5.946,6.416,6.890,7.357,7.635,8.182,10.654,1ms 13 | linearpipe-10,6,6,0,10s,0s,9529,0,952,0,10.005951635s,37.996s,380%,63%,3.135,5.066,5.777,6.271,6.787,7.288,7.589,8.193,11.945,1ms 14 | linearpipe-100,6,6,0,10s,0s,9492,0,949,0,10.005242619s,38.012s,380%,63%,3.735,5.135,5.808,6.295,6.813,7.279,7.588,8.127,11.450,1ms 15 | ideal,6,6,0,10s,0s,15334,0,1533,0,10.003618975s,59.472s,595%,99%,1.757,2.657,3.364,3.878,4.399,4.841,5.113,5.511,6.776,1.5ms 16 | locking,6,6,0,10s,0s,2644,0,264,0,10.021186992s,10.152s,101%,17%,2.461,19.644,21.458,22.577,23.825,25.098,26.086,29.663,36.825,1.5ms 17 | finelocking,6,6,0,10s,0s,8712,0,871,0,10.00522652s,34.916s,349%,58%,2.087,4.926,6.059,6.853,7.692,8.459,8.946,9.949,13.661,1.5ms 18 | linearpipe-0,6,6,0,10s,0s,7260,0,725,0,10.007094872s,29.484s,295%,49%,4.360,6.667,7.586,8.230,8.868,9.510,9.951,11.261,14.574,1.5ms 19 | linearpipe-1,6,6,0,10s,0s,8527,0,852,0,10.005451246s,34.528s,345%,58%,2.847,5.293,6.252,6.943,7.706,8.439,8.900,11.192,17.872,1.5ms 20 | linearpipe-10,6,6,0,10s,0s,9010,0,900,0,10.007169213s,36.056s,360%,60%,2.972,4.872,5.908,6.633,7.387,8.076,8.520,9.401,11.943,1.5ms 21 | linearpipe-100,6,6,0,10s,0s,9019,0,902,0,10.004093972s,36.112s,361%,60%,2.756,4.944,5.914,6.621,7.352,8.065,8.489,9.197,10.760,1.5ms 22 | ideal,6,6,0,10s,0s,15247,0,1524,0,10.005514211s,59.368s,593%,99%,1.040,2.297,3.204,3.887,4.597,5.225,5.588,6.178,13.861,2ms 23 | locking,6,6,0,10s,0s,2517,0,251,0,10.024540981s,10.104s,101%,17%,3.681,19.172,21.872,23.691,25.480,27.334,28.526,34.316,64.521,2ms 24 | finelocking,6,6,0,10s,0s,8330,0,832,0,10.008262395s,33.244s,332%,55%,2.048,4.680,6.137,7.200,8.204,9.163,9.784,11.035,21.388,2ms 25 | linearpipe-0,6,6,0,10s,0s,6780,0,677,0,10.008113089s,27.336s,273%,46%,3.658,6.788,8.010,8.848,9.685,10.469,10.935,11.719,13.259,2ms 26 | linearpipe-1,6,6,0,10s,0s,8158,0,815,0,10.006750802s,32.816s,328%,55%,2.862,5.261,6.453,7.318,8.209,9.082,9.594,10.474,13.322,2ms 27 | linearpipe-10,6,6,0,10s,0s,8602,0,860,0,10.007007974s,34.164s,341%,57%,2.261,4.741,6.026,6.954,7.890,8.780,9.287,10.249,11.705,2ms 28 | linearpipe-100,6,6,0,10s,0s,8470,0,847,0,10.005456609s,33.908s,339%,56%,2.612,4.767,6.056,7.029,8.003,8.950,9.564,10.895,17.162,2ms 29 | -------------------------------------------------------------------------------- /coffee/finelocking.csv: -------------------------------------------------------------------------------- 1 | 2 | ideal,1,1,0,4s,0s,998,0,248,0,4.016369852s,3.968s,99%,99%,3.980,3.982,3.984,3.987,4.002,4.109,4.225,4.349,4.464,0s 3 | locking,1,1,0,4s,0s,999,0,248,0,4.022021337s,3.98s,99%,99%,3.980,3.983,3.984,3.987,3.998,4.112,4.279,4.353,4.428,0s 4 | finelocking,1,1,0,4s,0s,998,0,248,0,4.022016203s,3.98s,99%,99%,3.981,3.983,3.985,3.987,3.994,4.112,4.279,4.367,7.427,0s 5 | linearpipe-0,1,1,0,4s,0s,1030,0,248,0,4.152010268s,4.1s,99%,99%,3.982,3.984,3.985,3.989,4.012,4.128,4.282,4.356,4.462,0s 6 | linearpipe-1,1,1,0,4s,0s,1029,0,248,0,4.142325856s,4.088s,99%,99%,3.982,3.984,3.985,3.988,3.998,4.106,4.276,4.349,4.476,0s 7 | ideal,2,2,0,4s,0s,2035,0,508,0,4.002923531s,7.916s,198%,99%,3.765,3.769,3.776,3.928,3.987,4.003,4.091,4.271,4.505,0s 8 | locking,2,2,0,4s,0s,1010,0,252,0,4.012868808s,3.988s,99%,50%,3.893,7.493,7.581,7.695,7.981,8.214,8.944,12.722,18.345,0s 9 | finelocking,2,2,0,4s,0s,2025,0,506,0,4.005102694s,7.908s,197%,99%,3.766,3.769,3.798,3.938,3.989,4.052,4.184,4.723,7.316,0s 10 | linearpipe-0,2,2,0,4s,0s,2095,0,523,0,4.005095127s,7.968s,199%,99%,3.767,3.769,3.771,3.798,3.825,3.890,3.962,4.233,4.863,0s 11 | linearpipe-1,2,2,0,4s,0s,2077,0,518,0,4.006259213s,7.904s,197%,99%,3.767,3.769,3.771,3.803,3.942,3.993,4.072,4.304,4.968,0s 12 | ideal,3,3,0,4s,0s,3099,0,774,0,4.004243015s,11.88s,297%,99%,3.765,3.769,3.800,3.826,3.869,3.915,3.952,4.240,4.741,0s 13 | locking,3,3,0,4s,0s,1042,0,260,0,4.013251765s,4.036s,101%,34%,3.803,11.104,11.249,11.361,11.465,11.882,12.532,16.154,20.628,0s 14 | finelocking,3,3,0,4s,0s,3089,0,771,0,4.005703401s,11.836s,295%,98%,3.766,3.770,3.801,3.831,3.880,3.978,4.126,4.275,5.839,0s 15 | linearpipe-0,3,3,0,4s,0s,2959,0,739,0,4.006034425s,11.692s,292%,97%,3.767,3.770,3.803,3.847,3.984,4.784,5.259,5.841,6.648,0s 16 | linearpipe-1,3,3,0,4s,0s,3047,0,761,0,4.004245742s,11.708s,292%,97%,3.767,3.771,3.826,3.918,4.011,4.078,4.161,4.462,6.875,0s 17 | ideal,4,4,0,4s,0s,4081,0,1019,0,4.004649777s,15.864s,396%,99%,3.766,3.801,3.838,3.872,3.902,3.938,3.983,4.318,6.520,0s 18 | locking,4,4,0,4s,0s,1041,0,259,0,4.013263315s,4.06s,101%,25%,3.772,15.074,15.166,15.239,15.332,15.415,15.871,20.767,25.566,0s 19 | finelocking,4,4,0,4s,0s,3838,0,958,0,4.004431525s,14.968s,374%,93%,3.843,4.036,4.082,4.124,4.176,4.267,4.355,5.949,8.841,0s 20 | linearpipe-0,4,4,0,4s,0s,3808,0,951,0,4.004995328s,14.928s,373%,93%,3.845,3.981,4.061,4.122,4.191,4.319,4.491,6.712,6.973,0s 21 | linearpipe-1,4,4,0,4s,0s,3917,0,978,0,4.004271778s,15.264s,381%,95%,3.770,3.856,3.984,4.059,4.127,4.235,4.363,4.662,8.237,0s 22 | ideal,5,5,0,4s,0s,5098,0,1273,0,4.003387622s,19.804s,495%,99%,3.869,3.872,3.874,3.877,3.884,3.916,3.981,4.224,5.534,0s 23 | locking,5,5,0,4s,0s,1054,0,262,0,4.016358666s,4.064s,101%,20%,3.770,18.571,18.822,18.970,19.099,19.206,19.556,22.796,27.505,0s 24 | finelocking,5,5,0,4s,0s,3812,0,952,0,4.004802378s,15.04s,376%,75%,3.888,5.136,5.170,5.204,5.251,5.362,6.053,6.426,9.338,0s 25 | linearpipe-0,5,5,0,4s,0s,3805,0,950,0,4.004499073s,15.072s,376%,75%,3.896,5.084,5.144,5.201,5.273,5.414,5.626,6.684,8.064,0s 26 | linearpipe-1,5,5,0,4s,0s,4032,0,1007,0,4.004508978s,15.984s,399%,80%,4.080,4.860,4.899,4.927,4.969,5.088,5.204,5.379,8.026,0s 27 | ideal,6,6,0,4s,0s,6097,0,1523,0,4.004231158s,23.792s,594%,99%,3.869,3.873,3.876,3.881,3.895,3.934,4.026,4.314,6.439,0s 28 | locking,6,6,0,4s,0s,1049,0,261,0,4.021273924s,4.068s,101%,17%,3.970,22.423,22.710,22.841,22.994,23.347,23.720,27.665,32.583,0s 29 | finelocking,6,6,0,4s,0s,3823,0,954,0,4.006006822s,15.088s,377%,63%,4.065,6.176,6.212,6.247,6.296,6.373,6.519,7.253,10.237,0s 30 | linearpipe-0,6,6,0,4s,0s,3833,0,957,0,4.005552296s,15.232s,380%,63%,4.001,6.106,6.173,6.223,6.281,6.413,6.561,7.171,9.205,0s 31 | linearpipe-1,6,6,0,4s,0s,4038,0,1008,0,4.005591597s,16.152s,403%,67%,4.069,5.847,5.888,5.921,5.965,6.036,6.107,6.526,8.959,0s 32 | -------------------------------------------------------------------------------- /coffee/multi.csv: -------------------------------------------------------------------------------- 1 | mode,par,maxprocs,maxq,dur,interval,ops,drops,thru,dthr,wall,exec,util,upar,min,p05,p25,p50,p75,p90,p95,p99,max,jitter 2 | multi-1,10,6,0,10s,0s,9574,0,956,0,10.01016311s,37.744s,377%,63%,3.958,10.304,10.358,10.415,10.492,10.610,10.717,10.995,13.285,0s 3 | multi-1,100,6,0,10s,0s,9632,0,954,0,10.100845579s,38.044s,377%,63%,3.860,103.753,104.222,104.667,105.245,105.762,106.174,109.499,113.504,0s 4 | multi-1,1000,6,0,10s,0s,10452,0,948,0,11.030892969s,41.608s,377%,63%,3.901,550.923,1053.696,1056.736,1058.992,1061.475,1062.530,1063.846,1064.802,0s 5 | multi-1,10000,6,0,10s,0s,19450,0,948,0,20.518049384s,1m17.28s,377%,63%,3.988,1052.777,5167.337,10301.941,10572.068,10582.590,10583.749,10585.914,10586.965,0s 6 | multi-2,10,6,0,10s,0s,15000,0,1499,0,10.005953857s,58.6s,586%,98%,3.908,6.050,6.371,6.648,6.862,7.039,7.253,7.820,10.056,0s 7 | multi-2,100,6,0,10s,0s,14991,0,1491,0,10.054600144s,58.576s,583%,97%,3.892,65.151,66.250,66.801,67.538,68.291,68.927,72.194,91.353,0s 8 | multi-2,1000,6,0,10s,0s,15416,0,1464,0,10.531577479s,1m0.436s,574%,96%,4.555,558.609,667.092,669.404,672.564,709.766,794.172,941.113,971.483,0s 9 | multi-2,10000,6,0,10s,0s,20347,0,1335,0,15.239129386s,1m19.648s,523%,87%,3.890,977.826,5015.910,6681.027,8211.122,9135.693,9460.246,9678.843,9701.832,0s 10 | multi-3,10,6,0,10s,0s,15096,0,1509,0,10.006588332s,59.048s,590%,98%,3.870,5.195,5.912,6.488,7.092,7.834,7.929,8.737,13.511,0s 11 | multi-3,100,6,0,10s,0s,15205,0,1515,0,10.035891085s,59.528s,593%,99%,3.893,53.170,63.306,64.697,65.935,66.909,67.312,68.918,112.008,0s 12 | multi-3,1000,6,0,10s,0s,14689,0,1419,0,10.351016128s,58.232s,563%,94%,3.881,392.109,650.940,653.431,779.920,888.993,909.526,933.819,988.705,0s 13 | multi-3,10000,6,0,10s,0s,23076,0,1515,0,15.233669616s,1m30.084s,591%,99%,3.890,728.902,3739.472,6597.712,7818.412,8254.625,8415.656,8540.482,8610.306,0s 14 | multi-4,10,6,0,10s,0s,15294,0,1528,0,10.006851706s,59.692s,597%,99%,3.870,3.873,3.876,3.886,4.087,6.615,7.665,7.878,12.003,0s 15 | multi-4,100,6,0,10s,0s,15276,0,1518,0,10.065793177s,59.672s,593%,99%,3.878,64.125,64.915,65.840,66.755,67.206,67.605,68.427,72.414,0s 16 | multi-4,1000,6,0,10s,0s,16098,0,1510,0,10.659833001s,1m3.08s,592%,99%,3.885,528.896,657.674,659.033,660.805,670.593,683.936,699.922,707.323,0s 17 | multi-4,10000,6,0,10s,0s,25169,0,1514,0,16.626805869s,1m38.456s,592%,99%,3.888,819.210,4085.678,6586.695,6588.643,6614.941,6627.777,6629.576,6632.139,0s 18 | multi-5,10,6,0,10s,0s,15262,0,1525,0,10.006410777s,59.66s,596%,99%,3.870,3.872,3.875,3.880,3.896,3.983,4.186,5.803,19.908,0s 19 | multi-5,100,6,0,10s,0s,15305,0,1521,0,10.065562205s,59.916s,595%,99%,3.877,62.948,64.478,65.527,66.320,67.028,67.815,70.361,76.664,0s 20 | multi-5,1000,6,0,10s,0s,16261,0,1526,0,10.654219818s,1m3.432s,595%,99%,3.879,556.449,653.636,654.754,655.681,656.555,657.004,657.863,660.769,0s 21 | multi-5,10000,6,0,10s,0s,23534,0,1515,0,15.532926326s,1m32.232s,594%,99%,3.870,3.875,659.254,5549.195,7162.141,7684.839,7754.078,7780.591,7841.951,0s 22 | multi-6,10,6,0,10s,0s,15331,0,1532,0,10.006098336s,59.816s,598%,100%,3.869,3.872,3.875,3.880,3.898,3.986,4.139,5.460,7.329,0s 23 | multi-6,100,6,0,10s,0s,15409,0,1532,0,10.059870579s,1m0.248s,599%,100%,3.869,3.872,3.874,3.880,3.894,3.952,4.064,4.404,6.990,0s 24 | multi-6,1000,6,0,10s,0s,17047,0,1536,0,11.099786321s,1m6.464s,599%,100%,3.869,3.872,3.874,3.879,3.891,3.944,4.033,4.333,268.629,0s 25 | multi-6,10000,6,0,10s,0s,22970,0,1535,0,14.960931577s,1m29.616s,599%,100%,3.856,3.872,3.874,3.879,3.893,3.945,4.048,4.296,5552.197,0s 26 | multi-7,10,6,0,10s,0s,15326,0,1532,0,10.005264754s,59.76s,597%,100%,3.870,3.872,3.875,3.880,3.897,3.980,4.137,5.435,7.293,0s 27 | multi-7,100,6,0,10s,0s,15460,0,1536,0,10.063496457s,1m0.256s,599%,100%,3.870,3.872,3.874,3.879,3.893,3.932,4.025,4.305,6.514,0s 28 | multi-7,1000,6,0,10s,0s,16068,0,1531,0,10.497699503s,1m2.808s,598%,100%,3.821,3.872,3.874,3.879,3.893,3.943,4.046,4.376,756.319,0s 29 | multi-7,10000,6,0,10s,0s,24268,0,1536,0,15.798440233s,1m34.6s,599%,100%,3.870,3.872,3.874,3.879,3.892,3.942,4.035,4.273,6.394,0s 30 | multi-8,10,6,0,10s,0s,15331,0,1532,0,10.008712315s,59.812s,598%,100%,3.868,3.873,3.875,3.880,3.899,3.992,4.123,5.505,9.413,0s 31 | multi-8,100,6,0,10s,0s,15396,0,1531,0,10.057611026s,1m0.236s,599%,100%,3.869,3.872,3.874,3.879,3.893,3.953,4.057,4.380,9.532,0s 32 | multi-8,1000,6,0,10s,0s,16292,0,1536,0,10.607562369s,1m3.52s,599%,100%,3.870,3.872,3.874,3.879,3.893,3.946,4.029,4.255,181.156,0s 33 | multi-8,10000,6,0,10s,0s,29052,0,1536,0,18.919583105s,1m53.296s,599%,100%,3.869,3.872,3.874,3.879,3.893,3.944,4.037,4.287,6150.540,0s 34 | multi-9,10,6,0,10s,0s,15332,0,1533,0,10.004265367s,59.768s,597%,100%,3.870,3.873,3.875,3.881,3.898,3.980,4.121,5.301,7.239,0s 35 | multi-9,100,6,0,10s,0s,15401,0,1536,0,10.026125764s,1m0.044s,599%,100%,3.870,3.872,3.874,3.879,3.892,3.934,4.029,4.312,6.421,0s 36 | multi-9,1000,6,0,10s,0s,15924,0,1531,0,10.402345032s,1m2.304s,599%,100%,3.870,3.872,3.874,3.879,3.892,3.941,4.058,4.368,858.987,0s 37 | multi-9,10000,6,0,10s,0s,23900,0,1466,0,16.297545229s,1m33.976s,577%,96%,3.869,3.874,543.405,5144.557,6870.946,6979.076,7031.951,7112.453,7281.073,0s 38 | multi-10,10,6,0,10s,0s,15280,0,1527,0,10.006260788s,59.792s,598%,100%,3.869,3.873,3.875,3.880,3.898,3.994,4.167,5.707,7.299,0s 39 | multi-10,100,6,0,10s,0s,15395,0,1536,0,10.020327537s,1m0.008s,599%,100%,3.870,3.872,3.874,3.879,3.892,3.935,4.027,4.300,6.746,0s 40 | multi-10,1000,6,0,10s,0s,17536,0,1536,0,11.415332045s,1m8.304s,598%,100%,3.869,3.872,3.874,3.879,3.892,3.941,4.041,4.313,6.406,0s 41 | multi-10,10000,6,0,10s,0s,30538,0,1532,0,19.927563045s,1m59.32s,599%,100%,3.869,3.872,3.874,3.879,3.893,3.947,4.049,4.364,2272.600,0s 42 | -------------------------------------------------------------------------------- /coffee/perf.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "runtime" 7 | "sort" 8 | "sync" 9 | "syscall" 10 | "time" 11 | ) 12 | 13 | type perfArg struct { 14 | mode string // mode name 15 | par int // request parallelism 16 | maxq int // maximum queue length 17 | dur time.Duration // test duration 18 | interval time.Duration // request interval 19 | } 20 | 21 | const perfArgHeader = "mode,par,maxprocs,maxq,dur,interval" 22 | 23 | func (arg perfArg) String() string { 24 | return fmt.Sprintf( 25 | "%s,%d,%d,%d,%s,%s", 26 | arg.mode, arg.par, runtime.GOMAXPROCS(0), 27 | arg.maxq, arg.dur, arg.interval) 28 | } 29 | 30 | const maxSamples = 10000 31 | 32 | type sampler struct { 33 | min, max time.Duration 34 | samples []time.Duration 35 | count int 36 | closed bool 37 | } 38 | 39 | func newSampler() *sampler { 40 | return &sampler{ 41 | samples: make([]time.Duration, 0, maxSamples), 42 | } 43 | } 44 | 45 | func (s *sampler) checkClosed(want bool) { 46 | if s.closed != want { 47 | panic(fmt.Sprintf("sampler: want closed=%v", want)) 48 | } 49 | } 50 | 51 | func (s *sampler) add(d time.Duration) { 52 | s.checkClosed(false) 53 | if s.count == 0 { 54 | s.min = d 55 | s.max = d 56 | } 57 | s.count++ 58 | if d < s.min { 59 | s.min = d 60 | } 61 | if d > s.max { 62 | s.max = d 63 | } 64 | // Decide whether to include elapsed in samples using 65 | // https://en.wikipedia.org/wiki/Reservoir_sampling#Algorithm_R 66 | if len(s.samples) < cap(s.samples) { 67 | s.samples = append(s.samples, d) 68 | } else if j := rand.Intn(s.count); j < len(s.samples) { 69 | s.samples[j] = d 70 | } 71 | } 72 | 73 | func (s *sampler) close() { 74 | s.closed = true 75 | sort.Slice(s.samples, func(i, j int) bool { 76 | return s.samples[i] < s.samples[j] 77 | }) 78 | } 79 | 80 | func (s *sampler) Min() time.Duration { 81 | s.checkClosed(true) 82 | return s.min 83 | } 84 | 85 | func (s *sampler) Max() time.Duration { 86 | s.checkClosed(true) 87 | return s.max 88 | } 89 | 90 | func (s *sampler) p(pct int) time.Duration { 91 | s.checkClosed(true) 92 | if len(s.samples) == 0 { 93 | return 0 94 | } 95 | return s.samples[len(s.samples)*pct/100] 96 | } 97 | 98 | const samplerHeader = "count,min,p05,p25,p50,p75,p90,p95,p99,max" 99 | 100 | func (s *sampler) String() string { 101 | s.checkClosed(true) 102 | return fmt.Sprintf( 103 | "%d,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f", 104 | s.count, 105 | s.Min().Seconds()*1000, 106 | s.p(5).Seconds()*1000, 107 | s.p(25).Seconds()*1000, 108 | s.p(50).Seconds()*1000, 109 | s.p(75).Seconds()*1000, 110 | s.p(90).Seconds()*1000, 111 | s.p(95).Seconds()*1000, 112 | s.p(99).Seconds()*1000, 113 | s.Max().Seconds()*1000) 114 | } 115 | 116 | func startUtil() func() (walltime, exectime time.Duration) { 117 | var ru1, ru2 syscall.Rusage 118 | syscall.Getrusage(syscall.RUSAGE_SELF, &ru1) 119 | start := time.Now() 120 | return func() (walltime, exectime time.Duration) { 121 | syscall.Getrusage(syscall.RUSAGE_SELF, &ru2) 122 | return time.Since(start), 123 | time.Duration(syscall.TimevalToNsec(ru2.Utime) - 124 | syscall.TimevalToNsec(ru1.Utime)) 125 | } 126 | } 127 | 128 | // perfTest runs f repeatedly until arg.dur elapses, then returns a 129 | // perfResult containing up to maxSamples uniformly selected 130 | // durations. If arg.interval > 0, it specifies the rate at which to 131 | // attempt requests and increment res.drops on failure. 132 | func perfTest(arg perfArg, f func()) (res perfResult) { 133 | // Pipeline: request generator -> workers -> sampler 134 | endUtil := startUtil() 135 | 136 | // Generate requests until arg.dur elapses 137 | stop := time.NewTimer(arg.dur) 138 | defer stop.Stop() 139 | var send *time.Ticker 140 | if arg.interval > 0 { 141 | send = time.NewTicker(arg.interval) 142 | defer send.Stop() 143 | } 144 | requests := make(chan time.Time, arg.maxq) 145 | go func() { 146 | defer close(requests) 147 | for { 148 | if send == nil { 149 | // No request interval: send whenever the queue has space. 150 | select { 151 | case <-stop.C: 152 | return 153 | case requests <- time.Now(): 154 | } 155 | } else { 156 | // Attempt to send a request periodically, drop if queue is full. 157 | select { 158 | case <-stop.C: 159 | return 160 | case <-send.C: 161 | } 162 | select { 163 | case requests <- time.Now(): 164 | default: 165 | res.drops++ 166 | } 167 | } 168 | } 169 | }() 170 | 171 | // Workers run f until requests closed. 172 | durations := make(chan time.Duration) 173 | var wg sync.WaitGroup 174 | wg.Add(arg.par) 175 | for i := 0; i < arg.par; i++ { 176 | go func() { 177 | defer wg.Done() 178 | for start := range requests { 179 | queueTime := time.Since(start) 180 | _ = queueTime // not currently used 181 | start = time.Now() 182 | f() 183 | durations <- time.Since(start) 184 | } 185 | }() 186 | } 187 | go func() { 188 | wg.Wait() 189 | close(durations) 190 | }() 191 | 192 | // Sampler populates result with samples. 193 | res.par = arg.par 194 | res.sampler = newSampler() 195 | defer res.sampler.close() 196 | for elapsed := range durations { 197 | res.sampler.add(elapsed) 198 | } 199 | res.walltime, res.exectime = endUtil() 200 | return 201 | } 202 | 203 | // A perfResult summarizes the results of a perfTest, including 204 | // throughput and a latency distribution. 205 | type perfResult struct { 206 | par int 207 | drops int // valid iff args.interval > 0 208 | exectime time.Duration 209 | walltime time.Duration 210 | sampler *sampler 211 | } 212 | 213 | func (res perfResult) opsPerSec() float64 { 214 | return float64(res.sampler.count) / res.walltime.Seconds() 215 | } 216 | 217 | func (res perfResult) dropsPerSec() float64 { 218 | return float64(res.drops) / res.walltime.Seconds() 219 | } 220 | 221 | func (res perfResult) utilization() float64 { 222 | return res.exectime.Seconds() / res.walltime.Seconds() 223 | } 224 | 225 | const perfResultHeader = "ops,drops,thru,dthr,wall,exec,util,upar,min,p05,p25,p50,p75,p90,p95,p99,max" 226 | 227 | func (res perfResult) String() string { 228 | return fmt.Sprintf( 229 | "%d,%d,%.0f,%.0f,%s,%s,%2.f%%,%2.f%%,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f", 230 | res.sampler.count, 231 | res.drops, 232 | res.opsPerSec(), 233 | res.dropsPerSec(), 234 | res.walltime, 235 | res.exectime, 236 | 100*res.utilization(), 237 | 100*res.utilization()/float64(runtime.GOMAXPROCS(0)), 238 | res.sampler.Min().Seconds()*1000, 239 | res.sampler.p(5).Seconds()*1000, 240 | res.sampler.p(25).Seconds()*1000, 241 | res.sampler.p(50).Seconds()*1000, 242 | res.sampler.p(75).Seconds()*1000, 243 | res.sampler.p(90).Seconds()*1000, 244 | res.sampler.p(95).Seconds()*1000, 245 | res.sampler.p(99).Seconds()*1000, 246 | res.sampler.Max().Seconds()*1000) 247 | } 248 | -------------------------------------------------------------------------------- /coffee/overload.csv: -------------------------------------------------------------------------------- 1 | mode,par,maxprocs,maxq,dur,interval,ops,drops,thru,dthr,wall,exec,util,upar,min,p05,p25,p50,p75,p90,p95,p99,max,jitter 2 | ideal,10,6,0,10s,0s,15283,0,1528,0,10.00437695s,59.8s,598%,100%,3.870,3.872,3.875,3.880,3.897,3.989,4.167,5.770,7.291,0s 3 | ideal,100,6,0,10s,0s,15333,0,1530,0,10.02414831s,59.924s,598%,100%,3.869,3.872,3.874,3.879,3.895,3.949,4.049,4.361,41.719,0s 4 | ideal,1000,6,0,10s,0s,16115,0,1472,0,10.94486642s,1m3.248s,578%,96%,3.868,3.872,3.874,3.881,3.897,3.984,4.151,11.877,636.284,0s 5 | ideal,10000,6,0,10s,0s,25326,0,1521,0,16.64593316s,1m38.86s,594%,99%,3.869,3.872,3.874,3.879,3.893,3.942,4.048,4.407,5716.576,0s 6 | locking,10,6,0,10s,0s,2467,0,246,0,10.038470126s,10.156s,101%,17%,3.793,37.746,38.401,39.902,40.040,44.620,50.063,59.264,68.977,0s 7 | locking,100,6,0,10s,0s,2484,0,239,0,10.402731718s,10.46s,101%,17%,6.418,398.935,399.360,400.884,425.273,460.938,480.318,498.300,526.917,0s 8 | locking,1000,6,0,10s,0s,3489,0,249,0,14.007256463s,14.152s,101%,17%,4.010,715.969,3530.583,3995.033,4019.403,4024.589,4024.701,4024.815,4041.257,0s 9 | locking,10000,6,0,10s,0s,12531,0,252,0,49.690339968s,49.972s,101%,17%,3.995,2524.302,12377.566,24320.200,36891.623,39361.857,39475.689,39607.289,39692.832,0s 10 | finelocking,10,6,0,10s,0s,9538,0,953,0,10.009609282s,37.72s,377%,63%,3.950,10.315,10.376,10.439,10.524,10.654,10.788,11.591,17.848,0s 11 | finelocking,100,6,0,10s,0s,9600,0,950,0,10.101853196s,38.108s,377%,63%,3.893,103.754,104.285,104.982,105.637,106.625,107.961,114.028,214.895,0s 12 | finelocking,1000,6,0,10s,0s,10441,0,946,0,11.03623192s,41.62s,377%,63%,3.899,564.789,1055.113,1058.268,1060.028,1061.950,1064.081,1069.325,1674.278,0s 13 | finelocking,10000,6,0,10s,0s,19446,0,948,0,20.515478485s,1m17.376s,377%,63%,3.880,1027.059,5110.891,10283.402,10558.359,10572.050,10585.576,10587.209,11269.434,0s 14 | parsteam,10,6,0,10s,0s,9512,0,950,0,10.009834285s,37.62s,376%,63%,2.908,10.368,10.431,10.479,10.540,10.653,10.796,11.440,19.555,0s 15 | parsteam,100,6,0,10s,0s,9588,0,949,0,10.101998731s,37.956s,376%,63%,3.044,104.423,104.774,105.091,105.715,106.304,106.767,109.990,207.822,0s 16 | parsteam,1000,6,0,10s,0s,10471,0,949,0,11.033882529s,41.808s,379%,63%,3.994,564.879,1052.053,1054.941,1056.670,1058.177,1059.088,1060.208,2035.116,0s 17 | parsteam,10000,6,0,10s,0s,19448,0,945,0,20.572818768s,1m17.54s,377%,63%,18.912,1090.905,5148.329,10302.252,10542.418,10550.209,10559.184,10567.316,16892.619,0s 18 | americano,10,6,0,10s,0s,9589,0,958,0,10.010173677s,28.284s,283%,47%,2.934,10.189,10.280,10.354,10.442,10.604,10.782,12.416,18.751,0s 19 | americano,100,6,0,10s,0s,9721,0,962,0,10.102241106s,28.596s,283%,47%,2.916,102.825,103.168,103.658,104.507,105.190,105.924,106.573,208.080,0s 20 | americano,1000,6,0,10s,0s,10535,0,955,0,11.026943362s,31.332s,284%,47%,2.963,542.151,1045.916,1048.308,1049.992,1051.591,1052.752,1056.530,1706.487,0s 21 | americano,10000,6,0,10s,0s,19533,0,959,0,20.362578887s,57.852s,284%,47%,2.911,1064.977,5130.062,10336.061,10443.596,10468.513,10476.148,10484.516,14817.964,0s 22 | espresso,10,6,0,10s,0s,10366,0,1036,0,10.009324614s,20.504s,205%,34%,1.895,9.505,9.564,9.620,9.711,9.850,9.934,10.226,21.396,0s 23 | espresso,100,6,0,10s,0s,10339,0,1024,0,10.095591124s,20.604s,204%,34%,1.922,95.750,96.188,96.807,98.099,99.481,101.882,115.490,186.388,0s 24 | espresso,1000,6,0,10s,0s,11303,0,1031,0,10.961055723s,22.312s,204%,34%,2.165,580.968,963.364,964.729,966.464,983.576,994.169,995.050,1928.105,0s 25 | espresso,10000,6,0,10s,0s,20292,0,1035,0,19.603304363s,39.996s,204%,34%,1.887,1007.683,4860.561,9612.980,9709.208,9724.386,9728.058,9730.831,18563.339,0s 26 | linearpipe-0,10,6,0,10s,0s,9544,0,953,0,10.009922144s,37.98s,379%,63%,4.174,10.233,10.319,10.391,10.501,10.759,10.907,12.508,16.761,0s 27 | linearpipe-0,100,6,0,10s,0s,9625,0,953,0,10.103507234s,38.332s,379%,63%,3.980,103.264,103.613,104.127,105.446,106.582,107.432,118.582,125.147,0s 28 | linearpipe-0,1000,6,0,10s,0s,10557,0,956,0,11.046451329s,42.076s,381%,63%,3.953,552.134,1043.903,1045.143,1046.768,1048.999,1049.879,1053.298,1054.000,0s 29 | linearpipe-0,10000,6,0,10s,0s,19525,0,950,0,20.555637413s,1m17.876s,379%,63%,6.897,1004.228,5075.000,10191.161,10561.682,10565.466,10586.470,10588.636,10590.807,0s 30 | linearpipe-1,10,6,0,10s,0s,10058,0,1005,0,10.009841615s,40.328s,403%,67%,4.144,9.708,9.795,9.867,10.013,10.158,10.383,11.749,18.913,0s 31 | linearpipe-1,100,6,0,10s,0s,10191,0,1009,0,10.100200013s,40.68s,403%,67%,4.094,97.770,98.059,98.665,99.795,100.807,101.267,102.884,106.247,0s 32 | linearpipe-1,1000,6,0,10s,0s,10989,0,999,0,10.994512414s,43.988s,400%,67%,4.085,560.077,991.177,994.686,999.136,1003.312,1047.083,1048.918,1050.470,0s 33 | linearpipe-1,10000,6,0,10s,0s,20048,0,1006,0,19.92987082s,1m20.144s,402%,67%,7.540,1008.094,4924.816,9929.730,9945.873,9949.825,9951.076,9952.463,9952.937,0s 34 | linearpipe-10,10,6,0,10s,0s,10075,0,1007,0,10.009101771s,40.316s,403%,67%,4.197,9.763,9.828,9.871,9.932,10.085,10.271,10.580,17.662,0s 35 | linearpipe-10,100,6,0,10s,0s,10162,0,1006,0,10.098336822s,40.864s,405%,67%,4.614,97.742,98.374,99.074,100.165,100.851,101.306,103.354,106.203,0s 36 | linearpipe-10,1000,6,0,10s,0s,11093,0,1010,0,10.978973958s,44.34s,404%,67%,4.111,557.736,984.151,988.719,992.598,996.499,997.644,999.032,1002.136,0s 37 | linearpipe-10,10000,6,0,10s,0s,20093,0,1009,0,19.907076377s,1m20.564s,405%,67%,8.838,991.276,4947.153,9889.247,9908.426,9915.501,9916.408,9918.479,9919.887,0s 38 | splitpipe-0,10,6,0,10s,0s,9786,0,978,0,10.009870119s,38.768s,387%,65%,2.977,10.066,10.118,10.160,10.235,10.432,10.560,11.406,12.290,0s 39 | splitpipe-0,100,6,0,10s,0s,9861,0,976,0,10.102471661s,39.076s,387%,64%,2.922,101.317,101.562,101.986,103.021,103.963,104.875,105.942,107.114,0s 40 | splitpipe-0,1000,6,0,10s,0s,10768,0,977,0,11.023715373s,42.652s,387%,64%,3.688,554.553,1020.922,1023.186,1024.433,1026.205,1026.635,1027.502,1028.624,0s 41 | splitpipe-0,10000,6,0,10s,0s,19747,0,974,0,20.265670888s,1m18.288s,386%,64%,10.451,992.102,5060.290,10140.978,10272.153,10281.043,10283.430,10285.183,10288.938,0s 42 | splitpipe-1,10,6,0,10s,0s,10108,0,1010,0,10.009406101s,40.316s,403%,67%,3.138,9.717,9.789,9.852,9.963,10.123,10.253,10.470,11.917,0s 43 | splitpipe-1,100,6,0,10s,0s,10203,0,1010,0,10.098967819s,40.7s,403%,67%,3.089,97.531,98.039,98.605,99.608,100.622,101.139,102.674,104.382,0s 44 | splitpipe-1,1000,6,0,10s,0s,11127,0,1013,0,10.982716207s,44.304s,403%,67%,3.484,549.136,983.195,986.788,989.402,990.926,991.981,992.808,993.245,0s 45 | splitpipe-1,10000,6,0,10s,0s,20107,0,1012,0,19.87506068s,1m20.308s,404%,67%,7.872,983.738,4902.575,9863.893,9886.368,9897.009,9899.443,9901.972,9902.481,0s 46 | americanopipe-0,10,6,0,10s,0s,9662,0,965,0,10.009727281s,29.1s,291%,48%,3.005,10.143,10.202,10.249,10.323,10.487,10.628,13.685,17.809,0s 47 | americanopipe-0,100,6,0,10s,0s,9811,0,971,0,10.102362417s,29.524s,292%,49%,2.937,102.127,102.384,102.660,103.367,104.070,104.366,105.722,106.561,0s 48 | americanopipe-0,1000,6,0,10s,0s,10698,0,969,0,11.041582252s,32.212s,292%,49%,2.939,550.151,1028.921,1029.816,1031.965,1035.107,1046.651,1047.287,1047.619,0s 49 | americanopipe-0,10000,6,0,10s,0s,19683,0,969,0,20.3106751s,59.18s,291%,49%,4.857,1009.201,4969.641,10025.391,10315.753,10319.031,10320.271,10322.888,10323.242,0s 50 | americanopipe-1,10,6,0,10s,0s,10055,0,1005,0,10.009218065s,30.364s,303%,51%,3.053,9.758,9.824,9.880,10.006,10.241,10.373,10.578,13.522,0s 51 | americanopipe-1,100,6,0,10s,0s,10142,0,1004,0,10.099409396s,30.904s,306%,51%,3.348,98.255,98.626,99.412,100.311,100.671,101.297,102.319,103.548,0s 52 | americanopipe-1,1000,6,0,10s,0s,11031,0,1003,0,10.992694342s,33.552s,305%,51%,2.977,539.241,994.265,996.464,998.403,1001.244,1001.897,1003.918,1004.469,0s 53 | americanopipe-1,10000,6,0,10s,0s,19993,0,1002,0,19.954961885s,1m0.676s,304%,51%,5.955,984.784,5004.239,9920.150,9941.090,10001.877,10003.828,10005.843,10018.743,0s 54 | espressopipe-0,10,6,0,10s,0s,9983,0,997,0,10.009414257s,19.756s,197%,33%,1.982,9.861,9.921,9.981,10.075,10.210,10.331,10.642,12.677,0s 55 | espressopipe-0,100,6,0,10s,0s,10034,0,994,0,10.099415865s,19.948s,198%,33%,1.996,99.370,99.742,100.199,101.232,102.012,102.594,106.647,112.745,0s 56 | espressopipe-0,1000,6,0,10s,0s,10813,0,982,0,11.007037202s,21.584s,196%,33%,1.953,555.808,1005.423,1009.313,1017.968,1047.819,1066.624,1068.826,1069.910,0s 57 | espressopipe-0,10000,6,0,10s,0s,19940,0,992,0,20.107551466s,39.656s,197%,33%,4.320,980.450,5035.652,10031.672,10064.693,10102.892,10108.015,10111.037,10112.111,0s 58 | espressopipe-1,10,6,0,10s,0s,10270,0,1026,0,10.00892789s,20.552s,205%,34%,2.163,9.526,9.620,9.705,9.812,10.021,10.136,10.302,13.647,0s 59 | espressopipe-1,100,6,0,10s,0s,10359,0,1026,0,10.097042448s,20.72s,205%,34%,2.058,96.038,96.559,97.120,98.058,99.415,100.051,100.894,101.701,0s 60 | espressopipe-1,1000,6,0,10s,0s,11255,0,1026,0,10.969501683s,22.668s,207%,34%,2.066,549.775,972.013,974.376,975.767,977.920,981.926,983.844,984.305,0s 61 | espressopipe-1,10000,6,0,10s,0s,20250,0,1027,0,19.709902762s,40.428s,205%,34%,7.483,991.281,4928.890,9711.152,9731.275,9744.623,9746.914,9749.681,9750.304,0s 62 | multi-1,10,6,0,10s,0s,9566,0,956,0,10.009358152s,37.72s,377%,63%,3.873,10.311,10.370,10.426,10.499,10.603,10.714,11.097,13.478,0s 63 | multi-1,100,6,0,10s,0s,9631,0,953,0,10.101131727s,38.072s,377%,63%,3.904,103.744,104.137,104.678,105.404,106.116,106.486,107.556,109.000,0s 64 | multi-1,1000,6,0,10s,0s,10431,0,945,0,11.041466939s,41.512s,376%,63%,3.898,561.165,1052.222,1054.842,1060.125,1075.231,1093.993,1095.446,1095.874,0s 65 | multi-1,10000,6,0,10s,0s,19409,0,947,0,20.502222047s,1m17.256s,377%,63%,3.900,988.880,5131.207,10356.365,10586.364,10615.967,10619.360,10622.387,10623.726,0s 66 | multi-2,10,6,0,10s,0s,14992,0,1498,0,10.005281742s,58.584s,586%,98%,3.929,6.066,6.386,6.649,6.861,7.028,7.245,7.813,10.399,0s 67 | multi-2,100,6,0,10s,0s,14926,0,1485,0,10.053475612s,58.504s,582%,97%,3.900,65.312,66.301,66.936,67.740,68.818,70.199,77.018,92.305,0s 68 | multi-2,1000,6,0,10s,0s,15499,0,1473,0,10.524353886s,1m0.576s,576%,96%,3.908,521.286,667.363,668.696,670.548,733.245,845.798,900.775,902.074,0s 69 | multi-2,10000,6,0,10s,0s,24747,0,1475,0,16.772105718s,1m36.744s,577%,96%,3.891,892.307,4097.002,6728.773,6855.522,6927.884,6929.897,6931.754,6934.189,0s 70 | multi-4,10,6,0,10s,0s,15193,0,1518,0,10.007635325s,59.608s,596%,99%,3.870,3.873,3.876,3.887,5.006,6.894,7.794,7.939,20.288,0s 71 | multi-4,100,6,0,10s,0s,14294,0,1420,0,10.065361696s,56.168s,558%,93%,3.880,64.320,65.669,66.994,77.406,79.219,79.822,81.429,106.991,0s 72 | multi-4,1000,6,0,10s,0s,16180,0,1518,0,10.65991635s,1m3.164s,593%,99%,3.884,511.389,657.355,658.533,659.562,660.569,661.085,661.948,663.463,0s 73 | multi-4,10000,6,0,10s,0s,25171,0,1517,0,16.594758267s,1m38.36s,593%,99%,3.882,800.585,4173.206,6587.565,6589.783,6592.431,6594.272,6595.914,6598.326,0s 74 | multipipe-1,10,6,0,10s,0s,10053,0,1004,0,10.00882702s,40.268s,402%,67%,4.129,9.703,9.778,9.840,9.956,10.078,10.169,13.658,17.814,0s 75 | multipipe-1,100,6,0,10s,0s,10207,0,1011,0,10.097909563s,40.784s,404%,67%,4.121,97.663,97.988,98.563,99.688,100.358,100.957,102.031,102.873,0s 76 | multipipe-1,1000,6,0,10s,0s,11000,0,1000,0,10.995136971s,44.196s,402%,67%,4.116,558.888,989.033,992.613,995.107,1024.515,1040.144,1042.309,1044.309,0s 77 | multipipe-1,10000,6,0,10s,0s,19972,0,995,0,20.072531447s,1m20.692s,402%,67%,6.780,1044.631,5112.449,9975.824,10025.467,10079.783,10084.753,10090.076,10091.157,0s 78 | multipipe-2,10,6,0,10s,0s,15039,0,1503,0,10.006411121s,58.78s,587%,98%,3.872,3.877,4.265,6.187,7.662,8.704,9.242,10.645,14.283,0s 79 | multipipe-2,100,6,0,10s,0s,15392,0,1530,0,10.059403531s,1m0.104s,597%,100%,5.884,56.097,61.404,64.665,68.244,71.701,73.855,78.483,87.789,0s 80 | multipipe-2,1000,6,0,10s,0s,16316,0,1528,0,10.679904524s,1m3.816s,598%,100%,5.936,538.334,647.542,651.645,655.822,660.231,663.691,679.068,701.204,0s 81 | multipipe-2,10000,6,0,10s,0s,25300,0,1531,0,16.520904422s,1m38.792s,598%,100%,3.900,834.756,4046.871,6519.862,6526.500,6531.390,6534.201,6538.917,6549.945,0s 82 | multipipe-4,10,6,0,10s,0s,15261,0,1525,0,10.007643058s,59.904s,599%,100%,3.871,3.874,3.876,3.882,3.901,3.995,4.190,6.828,15.144,0s 83 | multipipe-4,100,6,0,10s,0s,15434,0,1535,0,10.057508824s,1m0.22s,599%,100%,3.872,3.876,45.363,58.238,66.407,73.989,78.483,85.748,100.461,0s 84 | multipipe-4,1000,6,0,10s,0s,16339,0,1535,0,10.645819986s,1m3.764s,599%,100%,6.529,532.518,638.762,646.689,654.411,661.353,665.851,675.128,697.028,0s 85 | multipipe-4,10000,6,0,10s,0s,25255,0,1530,0,16.503300176s,1m38.78s,599%,100%,3.893,840.454,4204.929,6514.265,6547.015,6558.075,6563.514,6575.196,6594.088,0s 86 | -------------------------------------------------------------------------------- /coffee/varycpu.csv: -------------------------------------------------------------------------------- 1 | 2 | ideal,1,1,0,10s,0s,2553,0,248,0,10.275650864s,10.192s,99%,99%,3.981,3.983,3.984,3.987,3.997,4.107,4.266,4.345,4.404,0s 3 | locking,1,1,0,10s,0s,2555,0,248,0,10.283078452s,10.196s,99%,99%,3.982,3.983,3.984,3.987,3.995,4.104,4.268,4.339,4.392,0s 4 | finelocking,1,1,0,10s,0s,2446,0,239,0,10.213923779s,10.128s,99%,99%,3.981,3.983,3.984,3.987,4.028,4.269,6.302,7.439,8.640,0s 5 | parsteam,1,1,0,10s,0s,2434,0,240,0,10.124604246s,10.044s,99%,99%,3.981,3.983,3.985,3.988,4.028,4.271,4.591,7.167,8.633,0s 6 | americano,1,1,0,10s,0s,3281,0,324,0,10.123649427s,10.024s,99%,99%,2.985,2.987,2.988,2.990,2.995,3.105,3.325,5.231,7.522,0s 7 | espresso,1,1,0,10s,0s,4934,0,489,0,10.082257434s,9.968s,99%,99%,1.988,1.990,1.992,1.993,1.997,2.096,2.224,3.206,5.016,0s 8 | linearpipe-0,1,1,0,10s,0s,2460,0,242,0,10.153685724s,10.052s,99%,99%,3.982,3.984,3.985,3.988,4.024,4.232,4.342,7.374,9.639,0s 9 | linearpipe-1,1,1,0,10s,0s,2464,0,242,0,10.173940617s,10.088s,99%,99%,3.983,3.984,3.985,3.988,4.022,4.253,4.334,7.284,9.747,0s 10 | linearpipe-10,1,1,0,10s,0s,2572,0,248,0,10.356367044s,10.252s,99%,99%,3.982,3.984,3.985,3.988,3.998,4.109,4.275,4.342,4.424,0s 11 | splitpipe-0,1,1,0,10s,0s,2486,0,248,0,10.040652422s,9.94s,99%,99%,3.671,3.740,3.797,3.986,3.991,4.139,4.323,7.323,9.106,0s 12 | splitpipe-1,1,1,0,10s,0s,2641,0,262,0,10.083639353s,9.992s,99%,99%,3.576,3.703,3.752,3.791,3.842,3.923,4.145,4.234,4.830,0s 13 | americanopipe-0,1,1,0,10s,0s,3216,0,319,0,10.074649197s,9.964s,99%,99%,2.750,2.817,2.988,2.990,2.997,3.271,4.698,5.749,7.724,0s 14 | americanopipe-1,1,1,0,10s,0s,3349,0,331,0,10.113597311s,10.008s,99%,99%,2.985,2.987,2.989,2.990,2.995,3.095,3.231,3.341,3.401,0s 15 | espressopipe-0,1,1,0,10s,0s,5094,0,497,0,10.252236317s,10.156s,99%,99%,1.990,1.991,1.992,1.994,1.997,2.058,2.103,2.263,2.385,0s 16 | espressopipe-1,1,1,0,10s,0s,4985,0,497,0,10.038945787s,9.964s,99%,99%,1.990,1.991,1.992,1.994,1.997,2.093,2.107,2.267,2.596,0s 17 | multi-1,1,1,0,10s,0s,2555,0,248,0,10.284249466s,10.18s,99%,99%,3.980,3.983,3.984,3.987,3.993,4.105,4.272,4.343,4.394,0s 18 | multi-2,1,1,0,10s,0s,2553,0,248,0,10.275301416s,10.196s,99%,99%,3.980,3.983,3.985,3.987,3.996,4.103,4.266,4.342,4.461,0s 19 | multi-4,1,1,0,10s,0s,2449,0,239,0,10.26091041s,10.144s,99%,99%,3.982,3.983,3.985,3.987,4.034,4.279,6.302,7.618,9.689,0s 20 | multipipe-1,1,1,0,10s,0s,2573,0,248,0,10.360446228s,10.268s,99%,99%,3.983,3.984,3.985,3.988,3.995,4.108,4.276,4.353,4.902,0s 21 | multipipe-2,1,1,0,10s,0s,2517,0,248,0,10.13459163s,10.064s,99%,99%,3.982,3.984,3.985,3.988,3.996,4.099,4.280,4.372,4.722,0s 22 | multipipe-4,1,1,0,10s,0s,2545,0,248,0,10.246478029s,10.14s,99%,99%,3.982,3.984,3.985,3.988,3.999,4.098,4.283,4.375,4.466,0s 23 | ideal,2,2,0,10s,0s,5157,0,515,0,10.005525172s,19.78s,198%,99%,3.765,3.768,3.771,3.800,3.863,3.987,4.033,4.304,7.679,0s 24 | locking,2,2,0,10s,0s,2515,0,251,0,10.007364083s,10.04s,100%,50%,3.782,7.475,7.588,7.773,7.982,8.310,8.971,12.002,19.089,0s 25 | finelocking,2,2,0,10s,0s,5080,0,508,0,10.005358513s,19.632s,196%,98%,3.766,3.768,3.771,3.801,3.876,4.025,4.159,6.460,8.377,0s 26 | parsteam,2,2,0,10s,0s,5233,0,523,0,10.004232071s,19.904s,199%,99%,2.866,3.766,3.770,3.795,3.828,3.928,4.134,4.417,5.280,0s 27 | americano,2,2,0,10s,0s,6930,0,691,0,10.025911868s,19.756s,197%,99%,2.823,2.825,2.828,2.833,2.864,2.934,2.993,3.217,4.423,0s 28 | espresso,2,2,0,10s,0s,9879,0,987,0,10.004699809s,18.824s,188%,94%,1.882,1.938,2.002,2.006,2.034,2.083,2.136,2.304,2.975,0s 29 | linearpipe-0,2,2,0,10s,0s,5222,0,522,0,10.006440866s,19.888s,199%,99%,3.767,3.769,3.771,3.798,3.823,3.888,3.964,4.272,7.597,0s 30 | linearpipe-1,2,2,0,10s,0s,5181,0,518,0,10.007044541s,19.74s,197%,99%,3.766,3.769,3.771,3.802,3.885,3.985,4.113,4.396,8.062,0s 31 | linearpipe-10,2,2,0,10s,0s,5194,0,519,0,10.004492775s,19.74s,197%,99%,3.767,3.769,3.771,3.803,3.888,3.985,4.071,4.274,4.431,0s 32 | splitpipe-0,2,2,0,10s,0s,5192,0,519,0,10.002375034s,19.744s,197%,99%,2.825,3.772,3.803,3.829,3.861,3.920,4.002,4.410,6.052,0s 33 | splitpipe-1,2,2,0,10s,0s,5070,0,507,0,10.005171361s,19.304s,193%,96%,3.830,3.886,3.890,3.917,3.953,4.049,4.189,4.306,4.728,0s 34 | americanopipe-0,2,2,0,10s,0s,6883,0,688,0,10.00306077s,19.776s,198%,99%,2.824,2.826,2.828,2.843,2.877,2.947,3.169,4.517,6.298,0s 35 | americanopipe-1,2,2,0,10s,0s,6932,0,693,0,10.002505057s,19.784s,198%,99%,2.824,2.826,2.828,2.855,2.908,2.972,3.027,3.251,6.448,0s 36 | espressopipe-0,2,2,0,10s,0s,9763,0,976,0,10.002593503s,18.936s,189%,95%,1.884,1.947,1.953,1.983,2.023,2.107,2.290,3.386,7.172,0s 37 | espressopipe-1,2,2,0,10s,0s,9807,0,981,0,10.00139788s,18.712s,187%,94%,1.884,2.000,2.003,2.008,2.039,2.109,2.151,2.343,3.658,0s 38 | multi-1,2,2,0,10s,0s,5199,0,519,0,10.022172229s,19.764s,197%,99%,3.765,3.768,3.771,3.799,3.833,3.902,4.055,4.240,9.901,0s 39 | multi-2,2,2,0,10s,0s,5199,0,520,0,10.002951896s,19.776s,198%,99%,3.739,3.768,3.771,3.800,3.829,3.885,3.937,4.227,4.618,0s 40 | multi-4,2,2,0,10s,0s,5186,0,518,0,10.016075649s,19.808s,198%,99%,3.766,3.769,3.773,3.804,3.841,3.906,3.983,4.276,6.502,0s 41 | multipipe-1,2,2,0,10s,0s,5213,0,521,0,10.003054976s,19.836s,198%,99%,3.767,3.769,3.771,3.801,3.844,3.924,4.021,4.290,7.079,0s 42 | multipipe-2,2,2,0,10s,0s,5220,0,522,0,10.00489364s,19.904s,199%,99%,3.766,3.769,3.770,3.797,3.821,3.887,3.960,4.268,7.941,0s 43 | multipipe-4,2,2,0,10s,0s,5241,0,524,0,10.005463066s,19.924s,199%,100%,3.766,3.769,3.770,3.800,3.828,3.881,3.925,4.191,4.318,0s 44 | ideal,3,3,0,10s,0s,7512,0,751,0,10.003866517s,29.704s,297%,99%,3.765,3.769,3.797,3.821,3.868,3.942,5.962,6.636,8.764,0s 45 | locking,3,3,0,10s,0s,2519,0,252,0,10.009602244s,10.116s,101%,34%,3.804,11.350,11.957,11.962,11.969,11.987,12.062,14.824,20.733,0s 46 | finelocking,3,3,0,10s,0s,7637,0,763,0,10.004269553s,29.488s,295%,98%,3.766,3.771,3.817,3.869,3.931,4.022,4.184,4.378,8.522,0s 47 | parsteam,3,3,0,10s,0s,6869,0,687,0,10.003780546s,26.736s,267%,89%,2.826,3.863,4.038,4.320,4.713,4.885,4.945,5.492,8.129,0s 48 | americano,3,3,0,10s,0s,9787,0,978,0,10.002854332s,28.168s,282%,94%,2.826,3.000,3.012,3.041,3.079,3.146,3.217,3.401,4.931,0s 49 | espresso,3,3,0,10s,0s,10324,0,1032,0,10.002380266s,20.144s,201%,67%,1.884,2.833,2.837,2.870,2.922,3.022,3.082,3.525,5.727,0s 50 | linearpipe-0,3,3,0,10s,0s,7563,0,756,0,10.002753249s,29.5s,295%,98%,3.767,3.770,3.814,3.877,3.951,4.140,4.618,5.490,7.429,0s 51 | linearpipe-1,3,3,0,10s,0s,7680,0,768,0,10.004888758s,29.692s,297%,99%,3.767,3.770,3.807,3.872,3.949,4.041,4.175,4.427,7.145,0s 52 | linearpipe-10,3,3,0,10s,0s,7646,0,764,0,10.003995965s,29.608s,296%,99%,3.767,3.770,3.809,3.879,3.958,4.081,4.229,4.631,6.928,0s 53 | splitpipe-0,3,3,0,10s,0s,6970,0,697,0,10.003768169s,26.752s,267%,89%,2.842,3.770,3.809,3.992,4.786,4.844,4.890,5.143,7.293,0s 54 | splitpipe-1,3,3,0,10s,0s,7564,0,756,0,10.003620691s,29.1s,291%,97%,2.834,3.828,3.885,3.920,3.968,4.103,4.516,5.070,6.673,0s 55 | americanopipe-0,3,3,0,10s,0s,9929,0,993,0,10.003674513s,28.708s,287%,96%,2.831,2.891,2.938,2.993,3.050,3.141,3.237,3.469,6.110,0s 56 | americanopipe-1,3,3,0,10s,0s,9519,0,952,0,10.003108095s,28.204s,282%,94%,2.827,2.949,3.107,3.140,3.179,3.254,3.326,3.527,5.942,0s 57 | espressopipe-0,3,3,0,10s,0s,9670,0,967,0,10.002133566s,18.992s,190%,63%,1.925,2.897,2.933,2.979,3.036,3.208,4.526,5.044,7.824,0s 58 | espressopipe-1,3,3,0,10s,0s,10275,0,1027,0,10.002350086s,19.98s,200%,67%,2.017,2.820,2.831,2.859,2.896,3.000,3.240,4.631,6.074,0s 59 | multi-1,3,3,0,10s,0s,7567,0,756,0,10.004764876s,29.184s,292%,97%,3.765,3.769,3.800,3.829,3.881,4.139,4.411,6.391,8.146,0s 60 | multi-2,3,3,0,10s,0s,7746,0,774,0,10.003938721s,29.688s,297%,99%,3.765,3.769,3.792,3.809,3.850,3.901,3.948,4.326,7.597,0s 61 | multi-4,3,3,0,10s,0s,7756,0,775,0,10.003412329s,29.68s,297%,99%,3.765,3.769,3.799,3.814,3.855,3.903,3.942,4.317,4.668,0s 62 | multipipe-1,3,3,0,10s,0s,7658,0,766,0,10.003592975s,29.44s,294%,98%,3.769,3.771,3.806,3.863,3.935,4.032,4.255,4.940,6.804,0s 63 | multipipe-2,3,3,0,10s,0s,7747,0,774,0,10.006663041s,29.86s,298%,99%,3.767,3.770,3.795,3.817,3.862,3.921,4.041,5.489,8.314,0s 64 | multipipe-4,3,3,0,10s,0s,7796,0,779,0,10.006405604s,29.88s,299%,100%,3.767,3.770,3.796,3.814,3.853,3.903,3.955,4.442,6.886,0s 65 | ideal,4,4,0,10s,0s,10234,0,1023,0,10.003297023s,39.66s,396%,99%,3.766,3.800,3.836,3.870,3.903,3.942,3.976,4.268,6.123,0s 66 | locking,4,4,0,10s,0s,2509,0,251,0,10.013329711s,10.112s,101%,25%,3.804,15.129,15.772,15.953,15.962,15.976,16.018,24.297,30.245,0s 67 | finelocking,4,4,0,10s,0s,9605,0,960,0,10.004422741s,37.384s,374%,93%,3.808,4.038,4.090,4.125,4.182,4.266,4.381,4.663,7.973,0s 68 | parsteam,4,4,0,10s,0s,9631,0,963,0,10.004038578s,37.508s,375%,94%,2.829,3.039,4.089,4.136,4.191,4.631,5.088,5.399,7.398,0s 69 | americano,4,4,0,10s,0s,9603,0,960,0,10.003490921s,28.268s,283%,71%,2.829,3.078,4.077,4.119,4.174,4.630,5.090,5.612,9.104,0s 70 | espresso,4,4,0,10s,0s,10302,0,1030,0,10.003896995s,20.424s,204%,51%,1.885,3.781,3.818,3.853,3.897,3.949,4.005,4.857,8.797,0s 71 | linearpipe-0,4,4,0,10s,0s,8539,0,853,0,10.004801124s,33.356s,333%,83%,3.803,3.987,4.070,4.138,4.268,6.754,7.834,10.207,21.792,0s 72 | linearpipe-1,4,4,0,10s,0s,9738,0,973,0,10.003745415s,37.944s,379%,95%,3.772,3.852,3.979,4.057,4.128,4.266,4.452,6.274,7.660,0s 73 | linearpipe-10,4,4,0,10s,0s,9803,0,980,0,10.003167197s,38.14s,381%,95%,3.769,3.849,3.979,4.058,4.125,4.233,4.420,4.719,8.616,0s 74 | splitpipe-0,4,4,0,10s,0s,9648,0,964,0,10.00479353s,37.74s,377%,94%,2.995,3.947,4.004,4.046,4.104,4.285,4.487,6.551,7.832,0s 75 | splitpipe-1,4,4,0,10s,0s,9896,0,989,0,10.003170213s,38.596s,386%,96%,2.826,3.656,3.952,3.998,4.056,4.178,4.670,6.209,7.381,0s 76 | americanopipe-0,4,4,0,10s,0s,9732,0,973,0,10.00319021s,28.656s,286%,72%,2.963,3.936,3.985,4.026,4.080,4.211,4.423,6.323,8.129,0s 77 | americanopipe-1,4,4,0,10s,0s,10154,0,1015,0,10.003110091s,29.8s,298%,74%,3.028,3.784,3.830,3.870,3.929,4.040,4.195,6.230,8.478,0s 78 | espressopipe-0,4,4,0,10s,0s,9436,0,943,0,10.003341749s,18.92s,189%,47%,1.978,3.921,3.974,4.026,4.109,4.508,5.792,6.934,11.113,0s 79 | espressopipe-1,4,4,0,10s,0s,10255,0,1025,0,10.003575337s,20.404s,204%,51%,2.059,3.772,3.828,3.872,3.937,4.030,4.151,4.347,6.520,0s 80 | multi-1,4,4,0,10s,0s,9648,0,964,0,10.00395133s,37.52s,375%,94%,3.854,4.038,4.085,4.123,4.171,4.241,4.323,4.530,7.350,0s 81 | multi-2,4,4,0,10s,0s,10112,0,1011,0,10.002399298s,39.592s,396%,99%,3.765,3.802,3.845,3.880,3.922,3.985,4.075,6.095,7.202,0s 82 | multi-4,4,4,0,10s,0s,10168,0,1016,0,10.003299353s,39.608s,396%,99%,3.765,3.803,3.849,3.881,3.919,3.969,4.031,4.406,7.243,0s 83 | multipipe-1,4,4,0,10s,0s,9738,0,973,0,10.005025761s,38.032s,380%,95%,3.768,3.847,3.964,4.034,4.107,4.292,4.539,6.452,8.604,0s 84 | multipipe-2,4,4,0,10s,0s,10196,0,1019,0,10.004407138s,39.756s,397%,99%,3.768,3.803,3.849,3.882,3.926,4.001,4.089,4.837,7.201,0s 85 | multipipe-4,4,4,0,10s,0s,10270,0,1027,0,10.004813063s,39.88s,399%,100%,3.767,3.803,3.846,3.877,3.911,3.951,3.996,4.374,6.877,0s 86 | ideal,5,5,0,10s,0s,12729,0,1273,0,10.002844302s,49.56s,495%,99%,3.869,3.872,3.874,3.876,3.879,3.916,3.984,4.231,9.102,0s 87 | locking,5,5,0,10s,0s,2546,0,254,0,10.01879424s,10.14s,101%,20%,3.800,18.748,18.950,19.073,19.623,19.954,22.609,30.604,31.633,0s 88 | finelocking,5,5,0,10s,0s,9544,0,954,0,10.004973213s,37.596s,376%,75%,3.827,5.139,5.160,5.196,5.247,5.350,5.607,6.577,11.847,0s 89 | parsteam,5,5,0,10s,0s,9459,0,945,0,10.004746431s,37.32s,373%,75%,3.032,5.164,5.204,5.236,5.279,5.359,5.507,6.398,9.904,0s 90 | americano,5,5,0,10s,0s,9628,0,962,0,10.004619244s,28.296s,283%,57%,2.918,5.058,5.122,5.167,5.218,5.293,5.388,6.085,8.301,0s 91 | espresso,5,5,0,10s,0s,10317,0,1031,0,10.004400602s,20.46s,205%,41%,1.887,4.726,4.780,4.817,4.879,4.974,5.099,5.359,8.337,0s 92 | linearpipe-0,5,5,0,10s,0s,9249,0,924,0,10.005117493s,36.8s,368%,74%,4.094,5.087,5.145,5.206,5.293,5.644,6.985,8.565,12.338,0s 93 | linearpipe-1,5,5,0,10s,0s,10060,0,1006,0,10.00432618s,39.88s,399%,80%,3.902,4.857,4.899,4.930,4.977,5.116,5.247,5.503,7.990,0s 94 | linearpipe-10,5,5,0,10s,0s,10056,0,1005,0,10.004640089s,39.904s,399%,80%,3.927,4.859,4.898,4.930,4.976,5.115,5.296,5.533,8.134,0s 95 | splitpipe-0,5,5,0,10s,0s,9768,0,976,0,10.005304072s,38.472s,385%,77%,2.897,4.991,5.019,5.069,5.115,5.228,5.416,6.203,11.556,0s 96 | splitpipe-1,5,5,0,10s,0s,10137,0,1013,0,10.004350517s,39.9s,399%,80%,2.909,4.821,4.855,4.892,4.958,5.064,5.208,5.542,7.810,0s 97 | americanopipe-0,5,5,0,10s,0s,9681,0,968,0,10.005132742s,29.1s,291%,58%,3.052,5.031,5.076,5.126,5.180,5.303,5.467,5.797,8.872,0s 98 | americanopipe-1,5,5,0,10s,0s,9945,0,994,0,10.004601955s,30.336s,303%,61%,2.864,4.856,4.917,4.976,5.033,5.116,5.256,6.503,14.104,0s 99 | espressopipe-0,5,5,0,10s,0s,9964,0,996,0,10.004116806s,19.708s,197%,39%,1.922,4.891,4.949,4.998,5.058,5.131,5.201,5.429,8.651,0s 100 | espressopipe-1,5,5,0,10s,0s,10157,0,1015,0,10.004526009s,20.544s,205%,41%,1.885,4.756,4.839,4.901,4.978,5.071,5.165,5.352,7.905,0s 101 | multi-1,5,5,0,10s,0s,9520,0,952,0,10.004312604s,37.56s,375%,75%,3.890,5.141,5.166,5.201,5.251,5.340,5.494,6.166,10.116,0s 102 | multi-2,5,5,0,10s,0s,12721,0,1272,0,10.004558976s,49.476s,495%,99%,3.869,3.872,3.875,3.877,3.885,3.953,4.028,4.265,6.140,0s 103 | multi-4,5,5,0,10s,0s,12723,0,1272,0,10.004068159s,49.552s,495%,99%,3.870,3.872,3.874,3.877,3.882,3.941,4.044,4.241,6.637,0s 104 | multipipe-1,5,5,0,10s,0s,10067,0,1006,0,10.004836498s,39.908s,399%,80%,4.066,4.845,4.866,4.920,5.011,5.120,5.283,5.574,7.944,0s 105 | multipipe-2,5,5,0,10s,0s,12775,0,1277,0,10.004831971s,49.736s,497%,99%,3.871,3.874,3.875,3.877,3.890,4.002,4.066,4.403,6.467,0s 106 | multipipe-4,5,5,0,10s,0s,12825,0,1282,0,10.004903692s,49.924s,499%,100%,3.871,3.873,3.875,3.875,3.881,3.918,4.000,4.250,7.600,0s 107 | ideal,6,6,0,10s,0s,15132,0,1513,0,10.003755449s,59.436s,594%,99%,3.870,3.873,3.876,3.881,3.897,3.956,4.070,4.753,16.767,0s 108 | locking,6,6,0,10s,0s,2560,0,255,0,10.020844331s,10.128s,101%,17%,3.804,22.367,22.717,22.940,23.941,23.978,25.023,32.630,41.702,0s 109 | finelocking,6,6,0,10s,0s,9530,0,952,0,10.00590393s,37.676s,377%,63%,3.887,6.177,6.215,6.255,6.321,6.403,6.516,7.241,10.664,0s 110 | parsteam,6,6,0,10s,0s,9411,0,941,0,10.005479761s,37.54s,375%,63%,2.956,6.195,6.251,6.288,6.340,6.496,7.149,8.359,14.977,0s 111 | americano,6,6,0,10s,0s,9650,0,964,0,10.005773017s,28.336s,283%,47%,2.900,6.085,6.151,6.197,6.252,6.330,6.417,6.680,9.263,0s 112 | espresso,6,6,0,10s,0s,10276,0,1027,0,10.005203248s,20.38s,204%,34%,1.888,5.699,5.740,5.791,5.870,6.080,6.174,6.686,10.704,0s 113 | linearpipe-0,6,6,0,10s,0s,9537,0,953,0,10.006429109s,37.956s,379%,63%,3.900,6.116,6.185,6.237,6.298,6.450,6.638,7.297,13.326,0s 114 | linearpipe-1,6,6,0,10s,0s,10068,0,1006,0,10.005433491s,40.188s,402%,67%,3.893,5.841,5.886,5.922,5.972,6.076,6.233,6.525,10.160,0s 115 | linearpipe-10,6,6,0,10s,0s,9963,0,996,0,10.0047961s,39.916s,399%,66%,4.123,5.842,5.891,5.924,5.970,6.091,6.246,9.858,13.821,0s 116 | splitpipe-0,6,6,0,10s,0s,9756,0,975,0,10.005785662s,38.612s,386%,64%,2.952,6.027,6.064,6.095,6.147,6.258,6.430,7.294,10.720,0s 117 | splitpipe-1,6,6,0,10s,0s,10108,0,1010,0,10.005089821s,40.404s,404%,67%,3.146,5.809,5.860,5.906,5.975,6.064,6.189,6.446,9.674,0s 118 | americanopipe-0,6,6,0,10s,0s,9710,0,970,0,10.00546184s,29.252s,292%,49%,2.931,6.080,6.117,6.150,6.200,6.295,6.403,6.614,8.065,0s 119 | americanopipe-1,6,6,0,10s,0s,10048,0,1004,0,10.005302059s,30.484s,305%,51%,3.071,5.845,5.897,5.945,6.021,6.086,6.202,6.379,8.157,0s 120 | espressopipe-0,6,6,0,10s,0s,9959,0,995,0,10.00562938s,19.72s,197%,33%,1.920,5.902,5.948,5.993,6.064,6.160,6.267,6.510,9.404,0s 121 | espressopipe-1,6,6,0,10s,0s,10262,0,1026,0,10.005566114s,20.508s,205%,34%,2.206,5.687,5.754,5.815,5.897,6.024,6.168,6.334,9.399,0s 122 | multi-1,6,6,0,10s,0s,9555,0,955,0,10.005364528s,37.692s,377%,63%,3.956,6.176,6.210,6.246,6.296,6.375,6.467,7.072,9.206,0s 123 | multi-2,6,6,0,10s,0s,15196,0,1519,0,10.004181577s,59.328s,593%,99%,3.869,3.873,3.877,3.882,3.906,4.000,4.091,4.426,6.565,0s 124 | multi-4,6,6,0,10s,0s,15241,0,1524,0,10.003135348s,59.488s,595%,99%,3.870,3.873,3.876,3.881,3.896,3.943,4.029,4.266,6.456,0s 125 | multipipe-1,6,6,0,10s,0s,10060,0,1006,0,10.004959028s,40.328s,403%,67%,4.072,5.823,5.877,5.926,6.017,6.086,6.187,6.469,9.786,0s 126 | multipipe-2,6,6,0,10s,0s,15238,0,1523,0,10.0030257s,59.456s,594%,99%,3.871,3.874,3.877,3.886,3.956,4.063,4.134,4.405,6.405,0s 127 | multipipe-4,6,6,0,10s,0s,15269,0,1526,0,10.006003673s,59.904s,599%,100%,3.871,3.874,3.876,3.881,3.897,3.982,4.109,4.467,7.301,0s 128 | -------------------------------------------------------------------------------- /coffee/main.go: -------------------------------------------------------------------------------- 1 | // The coffee command simulates a small parallel pipeline and outputs CSV. 2 | // 3 | // The pipeline consists of three stages: grinding coffee beans, 4 | // preparing espresso, and steaming milk. Each stage contends on the 5 | // respective machine (grinder, espresso machine, steamer). 6 | // 7 | // This simulation reports throughput, latency, and utilization. 8 | // It can also create an execution trace with the --trace flag. 9 | package main 10 | 11 | import ( 12 | "flag" 13 | "fmt" 14 | "log" 15 | "math/rand" 16 | "os" 17 | "runtime" 18 | "runtime/trace" 19 | "strconv" 20 | "strings" 21 | "sync" 22 | "time" 23 | ) 24 | 25 | var ( 26 | mode = flag.String("mode", "ideal", `comma-separated list of modes: 27 | ideal: no synchronization, no contention overhead. Fails the race detector. 28 | locking: one lock, maximal contention. 29 | finelocking: one lock per machine, permitting greater parallelism. 30 | parsteam: finelocking with steaming happening in parallel with the other stages. 31 | americano: skip the steamMilk stage, but still makeLatte to add the water. 32 | espresso: skip the steamMilk and makeLatte stages. 33 | linearpipe-N: a pipeline with one goroutine per machine. 34 | splitpipe-N: a pipeline with the steamer stage happening in parallel with the other stages. 35 | multi-N: finelocking but with N copies of each machine. 36 | multipipe-N: N copies of linearpipe. 37 | `) 38 | duration = flag.Duration("dur", 1*time.Second, "perf test duration") 39 | interval = flag.Duration("interval", 0, "perf test request interval") 40 | grindTime = flag.Duration("grind", 1*time.Millisecond, "grind phase duration") 41 | pressTime = flag.Duration("press", 1*time.Millisecond, "press phase duration") 42 | steamTime = flag.Duration("steam", 1*time.Millisecond, "steam phase duration") 43 | latteTime = flag.Duration("latte", 1*time.Millisecond, "latte phase duration") 44 | jitter = flag.Duration("jitter", 0, "add uniform random duration in [-jitter/2,+jitter/2] to each phase") 45 | printDurs = flag.Bool("printdurs", false, "print duration distribution of each phase") 46 | traceFlag = flag.String("trace", "", "execution trace file, e.g., ./trace.out") 47 | header = flag.Bool("header", true, "whether to print CSV header") 48 | pars intList 49 | maxqs intList 50 | ) 51 | 52 | func init() { 53 | flag.Var(&pars, "par", "comma-separated list of perf test parallelism (how many brews to run in parallel)") 54 | flag.Var(&maxqs, "maxq", "comma-separated max lengths of the request queue (how many calls to queue up)") 55 | } 56 | 57 | type intList []int 58 | 59 | func (il *intList) Set(s string) error { 60 | ss := strings.Split(s, ",") 61 | for _, s := range ss { 62 | n, err := strconv.Atoi(s) 63 | if err != nil { 64 | return err 65 | } 66 | *il = append(*il, n) 67 | } 68 | return nil 69 | } 70 | 71 | func (il *intList) String() string { 72 | var ss []string 73 | for _, n := range *il { 74 | ss = append(ss, strconv.Itoa(n)) 75 | } 76 | return strings.Join(ss, ",") 77 | } 78 | 79 | // A machine keeps a count of how often it's been used and a sample of 80 | // latencies. 81 | type machine struct { 82 | name string 83 | sync.Mutex 84 | *sampler 85 | } 86 | 87 | func newMachine(name string) *machine { 88 | return &machine{ 89 | name: name, 90 | sampler: newSampler(), 91 | } 92 | } 93 | 94 | func (m *machine) close() { 95 | if m == nil { 96 | return 97 | } 98 | m.sampler.close() 99 | if *printDurs { 100 | log.Println(m.name, ":", m.sampler) 101 | } 102 | } 103 | 104 | // Shared state, requiring synchronization 105 | var ( 106 | grinder = newMachine("grinder") 107 | espressoMachine = newMachine("presser") 108 | steamer = newMachine("steamer") 109 | ) 110 | 111 | func resetMachines() { 112 | grinder.close() 113 | espressoMachine.close() 114 | steamer.close() 115 | grinder = newMachine("grinder") 116 | espressoMachine = newMachine("presser") 117 | steamer = newMachine("steamer") 118 | } 119 | 120 | // Named types for the pipeline elements. 121 | type ( 122 | grounds int 123 | coffee int 124 | milk int 125 | latte int 126 | ) 127 | 128 | // Ideal case: no contention (fails the race detector with par > 1) 129 | func idealBrew() latte { 130 | grounds := grindCoffee(grinder) 131 | coffee := makeEspresso(espressoMachine, grounds) 132 | milk := steamMilk(steamer) 133 | return makeLatte(coffee, milk) 134 | } 135 | 136 | // Simulate one millisecond of prep time. 137 | // Each stage adds a latency sample to the provided machine. 138 | // Synchronization must happen outside these stages. 139 | 140 | func runPhase(d, jitter time.Duration) time.Duration { 141 | if jitter > 0 { 142 | d += time.Duration(rand.Int63n((jitter).Nanoseconds())) 143 | d -= jitter / 2 144 | } 145 | start := time.Now() 146 | useCPU(d) 147 | return time.Since(start) 148 | } 149 | 150 | func grindCoffee(grinder *machine) grounds { 151 | grinder.add(runPhase(*grindTime, *jitter)) 152 | return grounds(0) 153 | } 154 | 155 | func makeEspresso(espressoMachine *machine, grounds grounds) coffee { 156 | espressoMachine.add(runPhase(*pressTime, *jitter)) 157 | return coffee(grounds) 158 | } 159 | 160 | func steamMilk(steamer *machine) milk { 161 | steamer.add(runPhase(*steamTime, *jitter)) 162 | return milk(0) 163 | } 164 | 165 | func makeLatte(coffee coffee, milk milk) latte { 166 | // No shared state to contend on. 167 | runPhase(*latteTime, 0) // no jitter 168 | return latte(int(coffee) + int(milk)) 169 | } 170 | 171 | // Locking case: contention on the whole kitchen. 172 | var kitchen sync.Mutex 173 | 174 | func lockingBrew() latte { 175 | kitchen.Lock() 176 | defer kitchen.Unlock() 177 | grounds := grindCoffee(grinder) 178 | coffee := makeEspresso(espressoMachine, grounds) 179 | milk := steamMilk(steamer) 180 | return makeLatte(coffee, milk) 181 | } 182 | 183 | // Fine-grain locking reduces contention. 184 | 185 | func fineLockingBrew() latte { 186 | grounds := lockingGrind() 187 | coffee := lockingPress(grounds) 188 | milk := lockingSteam() 189 | return makeLatte(coffee, milk) 190 | } 191 | 192 | func lockingGrind() grounds { 193 | grinder.Lock() 194 | defer grinder.Unlock() 195 | return grindCoffee(grinder) 196 | } 197 | 198 | func lockingPress(grounds grounds) coffee { 199 | espressoMachine.Lock() 200 | defer espressoMachine.Unlock() 201 | return makeEspresso(espressoMachine, grounds) 202 | } 203 | 204 | func lockingSteam() milk { 205 | steamer.Lock() 206 | defer steamer.Unlock() 207 | return steamMilk(steamer) 208 | } 209 | 210 | // Paralellizing operations can help, provided there's available CPU. 211 | // Can steam milk while grinding & pressing, but this loses to 212 | // fine-grain locking when all CPUs utilized. 213 | func parallelSteaming() latte { 214 | c := make(chan milk, 1) 215 | go func() { 216 | c <- lockingSteam() 217 | }() 218 | grounds := lockingGrind() 219 | coffee := lockingPress(grounds) 220 | milk := <-c 221 | return makeLatte(coffee, milk) 222 | } 223 | 224 | // Americano skips the steamMilk stage. This simulates making an RPC or doing a 225 | // cache lookup instead of burning CPU for that stage. This wins over 226 | // fine-grain locking. 227 | func americano() latte { 228 | grounds := lockingGrind() 229 | coffee := lockingPress(grounds) 230 | water := milk(0) 231 | return makeLatte(coffee, water) 232 | } 233 | 234 | // Espresso skips the steamMilk and makeLatte stages. This shows the benefit of 235 | // skipping optional work (and possibly delivering degraded results). 236 | func espresso() latte { 237 | grounds := lockingGrind() 238 | coffee := lockingPress(grounds) 239 | return latte(coffee) // no milk or water 240 | } 241 | 242 | // Multiple machines reduce contention. 243 | var grinders, espressoMachines, steamers chan *machine 244 | 245 | // newMachines returns a channel containing n machines in its buffer. 246 | func newMachines(name string, n int) chan *machine { 247 | c := make(chan *machine, n) 248 | for i := 0; i < n; i++ { 249 | c <- newMachine(fmt.Sprintf("%s%d", name, i)) 250 | } 251 | return c 252 | } 253 | 254 | func closeMachines(c chan *machine) { 255 | close(c) 256 | for m := range c { 257 | m.close() 258 | } 259 | } 260 | 261 | func multiBrew() latte { 262 | grounds := multiGrind() 263 | coffee := multiPress(grounds) 264 | milk := multiSteam() 265 | return makeLatte(coffee, milk) 266 | } 267 | 268 | func multiGrind() grounds { 269 | m := <-grinders 270 | grounds := grindCoffee(m) 271 | grinders <- m 272 | return grounds 273 | } 274 | 275 | func multiPress(grounds grounds) coffee { 276 | m := <-espressoMachines 277 | coffee := makeEspresso(m, grounds) 278 | espressoMachines <- m 279 | return coffee 280 | } 281 | 282 | func multiSteam() milk { 283 | m := <-steamers 284 | milk := steamMilk(m) 285 | steamers <- m 286 | return milk 287 | } 288 | 289 | // Linear pipeline 290 | type order struct { 291 | grounds grounds 292 | coffee coffee 293 | milk chan milk 294 | } 295 | 296 | type linearPipeline struct { 297 | grinderMachine *machine 298 | espressoMachine *machine 299 | steamerMachine *machine 300 | 301 | orders chan order 302 | ordersWithGrounds chan order 303 | ordersWithCoffee chan order 304 | done chan int 305 | } 306 | 307 | func newLinearPipeline(buffer int) *linearPipeline { 308 | p := &linearPipeline{ 309 | grinderMachine: newMachine("grinder"), 310 | espressoMachine: newMachine("presser"), 311 | steamerMachine: newMachine("steamer"), 312 | orders: make(chan order, buffer), 313 | ordersWithGrounds: make(chan order, buffer), 314 | ordersWithCoffee: make(chan order, buffer), 315 | done: make(chan int), 316 | } 317 | go p.grinder() 318 | go p.presser() 319 | go p.steamer() 320 | return p 321 | } 322 | 323 | // newLinearPipelineMulti returns a pipeline that uses a shared orders channel 324 | // from multiPipeline. 325 | func newLinearPipelineMulti(i int, orders chan order) *linearPipeline { 326 | p := &linearPipeline{ 327 | grinderMachine: newMachine(fmt.Sprintf("grinder%d", i)), 328 | espressoMachine: newMachine(fmt.Sprintf("presser%d", i)), 329 | steamerMachine: newMachine(fmt.Sprintf("steamer%d", i)), 330 | orders: orders, 331 | ordersWithGrounds: make(chan order, 10), // small buffer 332 | ordersWithCoffee: make(chan order, 10), 333 | done: make(chan int), 334 | } 335 | go p.grinder() 336 | go p.presser() 337 | go p.steamer() 338 | return p 339 | } 340 | 341 | func (p *linearPipeline) brew() latte { 342 | // Buffer result channel to prevent deadlock. 343 | o := order{milk: make(chan milk, 1)} 344 | p.orders <- o 345 | milk := <-o.milk 346 | return makeLatte(o.coffee, milk) 347 | } 348 | 349 | func (p *linearPipeline) grinder() { 350 | for o := range p.orders { 351 | o.grounds = grindCoffee(p.grinderMachine) 352 | p.ordersWithGrounds <- o 353 | } 354 | close(p.ordersWithGrounds) 355 | } 356 | 357 | func (p *linearPipeline) presser() { 358 | for o := range p.ordersWithGrounds { 359 | o.coffee = makeEspresso(p.espressoMachine, o.grounds) 360 | p.ordersWithCoffee <- o 361 | } 362 | close(p.ordersWithCoffee) 363 | } 364 | 365 | func (p *linearPipeline) steamer() { 366 | for o := range p.ordersWithCoffee { 367 | o.milk <- steamMilk(p.steamerMachine) 368 | } 369 | close(p.done) 370 | } 371 | 372 | func (p *linearPipeline) close() { 373 | close(p.orders) 374 | <-p.done 375 | p.grinderMachine.close() 376 | p.espressoMachine.close() 377 | p.steamerMachine.close() 378 | } 379 | 380 | // Americano pipeline skips the steamMilk step. 381 | func newAmericanoPipeline(buffer int) *linearPipeline { 382 | p := &linearPipeline{ 383 | grinderMachine: newMachine("grinder"), 384 | espressoMachine: newMachine("presser"), 385 | orders: make(chan order, buffer), 386 | ordersWithGrounds: make(chan order, buffer), 387 | done: make(chan int), 388 | } 389 | go p.grinder() 390 | go p.americanoPresser() 391 | return p 392 | } 393 | 394 | func (p *linearPipeline) americanoBrew() latte { 395 | // Buffer result channel to prevent deadlock. 396 | o := order{milk: make(chan milk, 1)} 397 | p.orders <- o 398 | water := <-o.milk 399 | return makeLatte(o.coffee, water) 400 | } 401 | 402 | func (p *linearPipeline) americanoPresser() { 403 | for o := range p.ordersWithGrounds { 404 | o.coffee = makeEspresso(p.espressoMachine, o.grounds) 405 | o.milk <- milk(0) // water 406 | } 407 | close(p.done) 408 | } 409 | 410 | // Espresso pipeline skips the steamMilk and makeLatte steps. 411 | func newEspressoPipeline(buffer int) *linearPipeline { 412 | p := &linearPipeline{ 413 | grinderMachine: newMachine("grinder"), 414 | espressoMachine: newMachine("presser"), 415 | orders: make(chan order, buffer), 416 | ordersWithGrounds: make(chan order, buffer), 417 | done: make(chan int), 418 | } 419 | go p.grinder() 420 | go p.americanoPresser() 421 | return p 422 | } 423 | 424 | func (p *linearPipeline) espressoBrew() latte { 425 | // Buffer result channel to prevent deadlock. 426 | o := order{milk: make(chan milk, 1)} 427 | p.orders <- o 428 | <-o.milk // espresso done 429 | return latte(o.coffee) // no milk or water 430 | } 431 | 432 | // Split pipeline 433 | type splitOrder struct { 434 | grounds grounds 435 | coffee chan coffee 436 | milk chan milk 437 | } 438 | type splitPipeline struct { 439 | grinderMachine *machine 440 | espressoMachine *machine 441 | steamerMachine *machine 442 | 443 | coffeeOrders chan splitOrder 444 | ordersWithGrounds chan splitOrder 445 | presserDone chan int 446 | 447 | milkOrders chan splitOrder 448 | steamerDone chan int 449 | } 450 | 451 | func newSplitPipeline(buffer int) *splitPipeline { 452 | p := &splitPipeline{ 453 | grinderMachine: newMachine("grinder"), 454 | espressoMachine: newMachine("presser"), 455 | steamerMachine: newMachine("steamer"), 456 | coffeeOrders: make(chan splitOrder, buffer), 457 | ordersWithGrounds: make(chan splitOrder, buffer), 458 | presserDone: make(chan int), 459 | milkOrders: make(chan splitOrder, buffer), 460 | steamerDone: make(chan int), 461 | } 462 | go p.grinder() 463 | go p.presser() 464 | go p.steamer() 465 | return p 466 | } 467 | 468 | func (p *splitPipeline) brew() latte { 469 | o := splitOrder{ 470 | // Buffer result channel to prevent deadlocks. 471 | coffee: make(chan coffee, 1), 472 | milk: make(chan milk, 1), 473 | } 474 | p.coffeeOrders <- o 475 | p.milkOrders <- o 476 | coffee := <-o.coffee 477 | milk := <-o.milk 478 | return makeLatte(coffee, milk) 479 | } 480 | 481 | func (p *splitPipeline) grinder() { 482 | for o := range p.coffeeOrders { 483 | o.grounds = grindCoffee(p.grinderMachine) 484 | p.ordersWithGrounds <- o 485 | } 486 | close(p.ordersWithGrounds) 487 | } 488 | 489 | func (p *splitPipeline) presser() { 490 | for o := range p.ordersWithGrounds { 491 | o.coffee <- makeEspresso(p.espressoMachine, o.grounds) 492 | } 493 | close(p.presserDone) 494 | } 495 | 496 | func (p *splitPipeline) steamer() { 497 | for o := range p.milkOrders { 498 | o.milk <- steamMilk(p.steamerMachine) 499 | } 500 | close(p.steamerDone) 501 | } 502 | 503 | func (p *splitPipeline) close() { 504 | close(p.coffeeOrders) 505 | <-p.presserDone 506 | close(p.milkOrders) 507 | <-p.steamerDone 508 | p.grinderMachine.close() 509 | p.espressoMachine.close() 510 | p.steamerMachine.close() 511 | } 512 | 513 | // Multiple copies of linearPipeline, like multiple coffee shops. 514 | type multiPipeline struct { 515 | orders chan order 516 | pipes chan *linearPipeline 517 | } 518 | 519 | func newMultiPipeline(n int) *multiPipeline { 520 | p := &multiPipeline{ 521 | orders: make(chan order), 522 | pipes: make(chan *linearPipeline, n), 523 | } 524 | for i := 0; i < n; i++ { 525 | p.pipes <- newLinearPipelineMulti(i, p.orders) 526 | } 527 | return p 528 | } 529 | 530 | func (p *multiPipeline) brew() latte { 531 | lp := <-p.pipes 532 | o := order{milk: make(chan milk, 1)} 533 | lp.orders <- o 534 | p.pipes <- lp // release the pipeline for other brew calls 535 | milk := <-o.milk // THEN wait for order to complete 536 | return makeLatte(o.coffee, milk) 537 | } 538 | 539 | func (p *multiPipeline) close() { 540 | close(p.orders) 541 | close(p.pipes) 542 | for lp := range p.pipes { 543 | <-lp.done 544 | lp.grinderMachine.close() 545 | lp.espressoMachine.close() 546 | lp.steamerMachine.close() 547 | } 548 | } 549 | 550 | func main() { 551 | rand.Seed(time.Now().UnixNano()) 552 | log.Print("GOMAXPROCS=", runtime.GOMAXPROCS(0)) 553 | flag.Parse() 554 | if len(pars) == 0 { 555 | pars = []int{1} 556 | } 557 | if len(maxqs) == 0 { 558 | maxqs = []int{0} 559 | } 560 | modes := strings.Split(*mode, ",") 561 | if len(modes) == 0 { 562 | modes = []string{"ideal"} 563 | } 564 | if *traceFlag != "" { 565 | traceFile, err := os.Create(*traceFlag) 566 | if err != nil { 567 | panic(err) 568 | } 569 | trace.Start(traceFile) 570 | defer func() { 571 | trace.Stop() 572 | if err := traceFile.Close(); err != nil { 573 | log.Panic(err) 574 | } 575 | }() 576 | } 577 | // Run all combinations of modes, parallelisms, and maxqs. 578 | // Print output as CSV. 579 | if *header { 580 | fmt.Println(perfArgHeader + "," + perfResultHeader + ",jitter") 581 | } 582 | for _, mode := range modes { 583 | f, close := modeFunc(mode) 584 | for _, par := range pars { 585 | if par == 0 { 586 | par = runtime.GOMAXPROCS(0) 587 | } 588 | for _, maxq := range maxqs { 589 | arg := perfArg{ 590 | mode: mode, 591 | par: par, 592 | maxq: maxq, 593 | dur: *duration, 594 | interval: *interval, 595 | } 596 | res := perfTest(arg, func() { f() }) 597 | fmt.Println(arg.String() + "," + res.String() + "," + (*jitter).String()) 598 | } 599 | } 600 | if close != nil { 601 | close() 602 | } 603 | } 604 | } 605 | 606 | func modeFunc(mode string) (func() latte, func()) { 607 | var n int 608 | switch { 609 | case mode == "ideal": 610 | return idealBrew, resetMachines 611 | case mode == "locking": 612 | return lockingBrew, resetMachines 613 | case modeParam(mode, "multi-", &n): 614 | grinders = newMachines("grinder", n) 615 | espressoMachines = newMachines("presser", n) 616 | steamers = newMachines("steamer", n) 617 | return multiBrew, func() { 618 | closeMachines(grinders) 619 | grinders = nil 620 | closeMachines(espressoMachines) 621 | espressoMachines = nil 622 | closeMachines(steamers) 623 | steamers = nil 624 | } 625 | case mode == "finelocking": 626 | return fineLockingBrew, resetMachines 627 | case mode == "parsteam": 628 | return parallelSteaming, resetMachines 629 | case mode == "americano": 630 | return americano, resetMachines 631 | case mode == "espresso": 632 | return espresso, resetMachines 633 | case modeParam(mode, "linearpipe-", &n): 634 | p := newLinearPipeline(n) 635 | return p.brew, p.close 636 | case modeParam(mode, "americanopipe-", &n): 637 | p := newAmericanoPipeline(n) 638 | return p.americanoBrew, p.close 639 | case modeParam(mode, "espressopipe-", &n): 640 | p := newEspressoPipeline(n) 641 | return p.espressoBrew, p.close 642 | case modeParam(mode, "splitpipe-", &n): 643 | p := newSplitPipeline(n) 644 | return p.brew, p.close 645 | case modeParam(mode, "multipipe-", &n): 646 | p := newMultiPipeline(n) 647 | return p.brew, p.close 648 | } 649 | log.Panicf("unknown mode: %s", mode) 650 | return nil, nil 651 | } 652 | 653 | func modeParam(mode, prefix string, n *int) bool { 654 | if !strings.HasPrefix(mode, prefix) { 655 | return false 656 | } 657 | var err error 658 | *n, err = strconv.Atoi((mode)[len(prefix):]) 659 | if err != nil { 660 | log.Panicf("bad mode %s: %v", mode, err) 661 | } 662 | return true 663 | } 664 | --------------------------------------------------------------------------------