12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099 |
- #!/usr/bin/env ruby
- # Copyright (C) 2011 Apple Inc. All rights reserved.
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions
- # are met:
- # 1. Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- # 2. Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in the
- # documentation and/or other materials provided with the distribution.
- #
- # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- # THE POSSIBILITY OF SUCH DAMAGE.
- require 'rubygems'
- require 'getoptlong'
- require 'pathname'
- require 'tempfile'
- require 'socket'
- begin
- require 'json'
- rescue LoadError => e
- $stderr.puts "It does not appear that you have the 'json' package installed. Try running 'sudo gem install json'."
- exit 1
- end
- # Configuration
- CONFIGURATION_FLNM = ENV["HOME"]+"/.bencher"
- unless FileTest.exist? CONFIGURATION_FLNM
- $stderr.puts "Error: no configuration file at ~/.bencher."
- $stderr.puts "This file should contain paths to SunSpider, V8, and Kraken, as well as a"
- $stderr.puts "temporary directory that bencher can use for its remote mode. It should be"
- $stderr.puts "formatted in JSON. For example:"
- $stderr.puts "{"
- $stderr.puts " \"sunSpiderPath\": \"/Volumes/Data/pizlo/OpenSource/PerformanceTests/SunSpider/tests/sunspider-1.0\","
- $stderr.puts " \"v8Path\": \"/Volumes/Data/pizlo/OpenSource/PerformanceTests/SunSpider/tests/v8-v6\","
- $stderr.puts " \"krakenPath\": \"/Volumes/Data/pizlo/kraken/kraken-e119421cb325/tests/kraken-1.1\","
- $stderr.puts " \"tempPath\": \"/Volumes/Data/pizlo/bencher/temp\""
- $stderr.puts "}"
- exit 1
- end
- CONFIGURATION = JSON.parse(File::read(CONFIGURATION_FLNM))
- SUNSPIDER_PATH = CONFIGURATION["sunSpiderPath"]
- V8_PATH = CONFIGURATION["v8Path"]
- KRAKEN_PATH = CONFIGURATION["krakenPath"]
- TEMP_PATH = CONFIGURATION["tempPath"]
- BENCH_DATA_PATH = TEMP_PATH + "/benchdata"
- IBR_LOOKUP=[0.00615583, 0.0975, 0.22852, 0.341628, 0.430741, 0.500526, 0.555933,
- 0.600706, 0.637513, 0.668244, 0.694254, 0.716537, 0.735827, 0.752684,
- 0.767535, 0.780716, 0.792492, 0.803074, 0.812634, 0.821313, 0.829227,
- 0.836472, 0.843129, 0.849267, 0.854943, 0.860209, 0.865107, 0.869674,
- 0.873942, 0.877941, 0.881693, 0.885223, 0.888548, 0.891686, 0.894652,
- 0.897461, 0.900124, 0.902652, 0.905056, 0.907343, 0.909524, 0.911604,
- 0.91359, 0.91549, 0.917308, 0.919049, 0.920718, 0.92232, 0.923859, 0.925338,
- 0.926761, 0.92813, 0.929449, 0.930721, 0.931948, 0.933132, 0.934275, 0.93538,
- 0.936449, 0.937483, 0.938483, 0.939452, 0.940392, 0.941302, 0.942185,
- 0.943042, 0.943874, 0.944682, 0.945467, 0.94623, 0.946972, 0.947694,
- 0.948396, 0.94908, 0.949746, 0.950395, 0.951027, 0.951643, 0.952244,
- 0.952831, 0.953403, 0.953961, 0.954506, 0.955039, 0.955559, 0.956067,
- 0.956563, 0.957049, 0.957524, 0.957988, 0.958443, 0.958887, 0.959323,
- 0.959749, 0.960166, 0.960575, 0.960975, 0.961368, 0.961752, 0.962129,
- 0.962499, 0.962861, 0.963217, 0.963566, 0.963908, 0.964244, 0.964574,
- 0.964897, 0.965215, 0.965527, 0.965834, 0.966135, 0.966431, 0.966722,
- 0.967007, 0.967288, 0.967564, 0.967836, 0.968103, 0.968366, 0.968624,
- 0.968878, 0.969128, 0.969374, 0.969617, 0.969855, 0.97009, 0.970321,
- 0.970548, 0.970772, 0.970993, 0.97121, 0.971425, 0.971636, 0.971843,
- 0.972048, 0.97225, 0.972449, 0.972645, 0.972839, 0.973029, 0.973217,
- 0.973403, 0.973586, 0.973766, 0.973944, 0.97412, 0.974293, 0.974464,
- 0.974632, 0.974799, 0.974963, 0.975125, 0.975285, 0.975443, 0.975599,
- 0.975753, 0.975905, 0.976055, 0.976204, 0.97635, 0.976495, 0.976638,
- 0.976779, 0.976918, 0.977056, 0.977193, 0.977327, 0.97746, 0.977592,
- 0.977722, 0.97785, 0.977977, 0.978103, 0.978227, 0.978349, 0.978471,
- 0.978591, 0.978709, 0.978827, 0.978943, 0.979058, 0.979171, 0.979283,
- 0.979395, 0.979504, 0.979613, 0.979721, 0.979827, 0.979933, 0.980037,
- 0.98014, 0.980242, 0.980343, 0.980443, 0.980543, 0.980641, 0.980738,
- 0.980834, 0.980929, 0.981023, 0.981116, 0.981209, 0.9813, 0.981391, 0.981481,
- 0.981569, 0.981657, 0.981745, 0.981831, 0.981916, 0.982001, 0.982085,
- 0.982168, 0.982251, 0.982332, 0.982413, 0.982493, 0.982573, 0.982651,
- 0.982729, 0.982807, 0.982883, 0.982959, 0.983034, 0.983109, 0.983183,
- 0.983256, 0.983329, 0.983401, 0.983472, 0.983543, 0.983613, 0.983683,
- 0.983752, 0.98382, 0.983888, 0.983956, 0.984022, 0.984089, 0.984154,
- 0.984219, 0.984284, 0.984348, 0.984411, 0.984474, 0.984537, 0.984599,
- 0.98466, 0.984721, 0.984782, 0.984842, 0.984902, 0.984961, 0.985019,
- 0.985077, 0.985135, 0.985193, 0.985249, 0.985306, 0.985362, 0.985417,
- 0.985472, 0.985527, 0.985582, 0.985635, 0.985689, 0.985742, 0.985795,
- 0.985847, 0.985899, 0.985951, 0.986002, 0.986053, 0.986103, 0.986153,
- 0.986203, 0.986252, 0.986301, 0.98635, 0.986398, 0.986446, 0.986494,
- 0.986541, 0.986588, 0.986635, 0.986681, 0.986727, 0.986773, 0.986818,
- 0.986863, 0.986908, 0.986953, 0.986997, 0.987041, 0.987084, 0.987128,
- 0.987171, 0.987213, 0.987256, 0.987298, 0.98734, 0.987381, 0.987423,
- 0.987464, 0.987504, 0.987545, 0.987585, 0.987625, 0.987665, 0.987704,
- 0.987744, 0.987783, 0.987821, 0.98786, 0.987898, 0.987936, 0.987974,
- 0.988011, 0.988049, 0.988086, 0.988123, 0.988159, 0.988196, 0.988232,
- 0.988268, 0.988303, 0.988339, 0.988374, 0.988409, 0.988444, 0.988479,
- 0.988513, 0.988547, 0.988582, 0.988615, 0.988649, 0.988682, 0.988716,
- 0.988749, 0.988782, 0.988814, 0.988847, 0.988879, 0.988911, 0.988943,
- 0.988975, 0.989006, 0.989038, 0.989069, 0.9891, 0.989131, 0.989161, 0.989192,
- 0.989222, 0.989252, 0.989282, 0.989312, 0.989342, 0.989371, 0.989401,
- 0.98943, 0.989459, 0.989488, 0.989516, 0.989545, 0.989573, 0.989602, 0.98963,
- 0.989658, 0.989685, 0.989713, 0.98974, 0.989768, 0.989795, 0.989822,
- 0.989849, 0.989876, 0.989902, 0.989929, 0.989955, 0.989981, 0.990007,
- 0.990033, 0.990059, 0.990085, 0.99011, 0.990136, 0.990161, 0.990186,
- 0.990211, 0.990236, 0.990261, 0.990285, 0.99031, 0.990334, 0.990358,
- 0.990383, 0.990407, 0.99043, 0.990454, 0.990478, 0.990501, 0.990525,
- 0.990548, 0.990571, 0.990594, 0.990617, 0.99064, 0.990663, 0.990686,
- 0.990708, 0.990731, 0.990753, 0.990775, 0.990797, 0.990819, 0.990841,
- 0.990863, 0.990885, 0.990906, 0.990928, 0.990949, 0.99097, 0.990991,
- 0.991013, 0.991034, 0.991054, 0.991075, 0.991096, 0.991116, 0.991137,
- 0.991157, 0.991178, 0.991198, 0.991218, 0.991238, 0.991258, 0.991278,
- 0.991298, 0.991317, 0.991337, 0.991356, 0.991376, 0.991395, 0.991414,
- 0.991433, 0.991452, 0.991471, 0.99149, 0.991509, 0.991528, 0.991547,
- 0.991565, 0.991584, 0.991602, 0.99162, 0.991639, 0.991657, 0.991675,
- 0.991693, 0.991711, 0.991729, 0.991746, 0.991764, 0.991782, 0.991799,
- 0.991817, 0.991834, 0.991851, 0.991869, 0.991886, 0.991903, 0.99192,
- 0.991937, 0.991954, 0.991971, 0.991987, 0.992004, 0.992021, 0.992037,
- 0.992054, 0.99207, 0.992086, 0.992103, 0.992119, 0.992135, 0.992151,
- 0.992167, 0.992183, 0.992199, 0.992215, 0.99223, 0.992246, 0.992262,
- 0.992277, 0.992293, 0.992308, 0.992324, 0.992339, 0.992354, 0.992369,
- 0.992384, 0.9924, 0.992415, 0.992429, 0.992444, 0.992459, 0.992474, 0.992489,
- 0.992503, 0.992518, 0.992533, 0.992547, 0.992561, 0.992576, 0.99259,
- 0.992604, 0.992619, 0.992633, 0.992647, 0.992661, 0.992675, 0.992689,
- 0.992703, 0.992717, 0.99273, 0.992744, 0.992758, 0.992771, 0.992785,
- 0.992798, 0.992812, 0.992825, 0.992839, 0.992852, 0.992865, 0.992879,
- 0.992892, 0.992905, 0.992918, 0.992931, 0.992944, 0.992957, 0.99297,
- 0.992983, 0.992995, 0.993008, 0.993021, 0.993034, 0.993046, 0.993059,
- 0.993071, 0.993084, 0.993096, 0.993109, 0.993121, 0.993133, 0.993145,
- 0.993158, 0.99317, 0.993182, 0.993194, 0.993206, 0.993218, 0.99323, 0.993242,
- 0.993254, 0.993266, 0.993277, 0.993289, 0.993301, 0.993312, 0.993324,
- 0.993336, 0.993347, 0.993359, 0.99337, 0.993382, 0.993393, 0.993404,
- 0.993416, 0.993427, 0.993438, 0.993449, 0.99346, 0.993472, 0.993483,
- 0.993494, 0.993505, 0.993516, 0.993527, 0.993538, 0.993548, 0.993559,
- 0.99357, 0.993581, 0.993591, 0.993602, 0.993613, 0.993623, 0.993634,
- 0.993644, 0.993655, 0.993665, 0.993676, 0.993686, 0.993697, 0.993707,
- 0.993717, 0.993727, 0.993738, 0.993748, 0.993758, 0.993768, 0.993778,
- 0.993788, 0.993798, 0.993808, 0.993818, 0.993828, 0.993838, 0.993848,
- 0.993858, 0.993868, 0.993877, 0.993887, 0.993897, 0.993907, 0.993916,
- 0.993926, 0.993935, 0.993945, 0.993954, 0.993964, 0.993973, 0.993983,
- 0.993992, 0.994002, 0.994011, 0.99402, 0.99403, 0.994039, 0.994048, 0.994057,
- 0.994067, 0.994076, 0.994085, 0.994094, 0.994103, 0.994112, 0.994121,
- 0.99413, 0.994139, 0.994148, 0.994157, 0.994166, 0.994175, 0.994183,
- 0.994192, 0.994201, 0.99421, 0.994218, 0.994227, 0.994236, 0.994244,
- 0.994253, 0.994262, 0.99427, 0.994279, 0.994287, 0.994296, 0.994304,
- 0.994313, 0.994321, 0.994329, 0.994338, 0.994346, 0.994354, 0.994363,
- 0.994371, 0.994379, 0.994387, 0.994395, 0.994404, 0.994412, 0.99442,
- 0.994428, 0.994436, 0.994444, 0.994452, 0.99446, 0.994468, 0.994476,
- 0.994484, 0.994492, 0.9945, 0.994508, 0.994516, 0.994523, 0.994531, 0.994539,
- 0.994547, 0.994554, 0.994562, 0.99457, 0.994577, 0.994585, 0.994593, 0.9946,
- 0.994608, 0.994615, 0.994623, 0.994631, 0.994638, 0.994645, 0.994653,
- 0.99466, 0.994668, 0.994675, 0.994683, 0.99469, 0.994697, 0.994705, 0.994712,
- 0.994719, 0.994726, 0.994734, 0.994741, 0.994748, 0.994755, 0.994762,
- 0.994769, 0.994777, 0.994784, 0.994791, 0.994798, 0.994805, 0.994812,
- 0.994819, 0.994826, 0.994833, 0.99484, 0.994847, 0.994854, 0.99486, 0.994867,
- 0.994874, 0.994881, 0.994888, 0.994895, 0.994901, 0.994908, 0.994915,
- 0.994922, 0.994928, 0.994935, 0.994942, 0.994948, 0.994955, 0.994962,
- 0.994968, 0.994975, 0.994981, 0.994988, 0.994994, 0.995001, 0.995007,
- 0.995014, 0.99502, 0.995027, 0.995033, 0.99504, 0.995046, 0.995052, 0.995059,
- 0.995065, 0.995071, 0.995078, 0.995084, 0.99509, 0.995097, 0.995103,
- 0.995109, 0.995115, 0.995121, 0.995128, 0.995134, 0.99514, 0.995146,
- 0.995152, 0.995158, 0.995164, 0.995171, 0.995177, 0.995183, 0.995189,
- 0.995195, 0.995201, 0.995207, 0.995213, 0.995219, 0.995225, 0.995231,
- 0.995236, 0.995242, 0.995248, 0.995254, 0.99526, 0.995266, 0.995272,
- 0.995277, 0.995283, 0.995289, 0.995295, 0.995301, 0.995306, 0.995312,
- 0.995318, 0.995323, 0.995329, 0.995335, 0.99534, 0.995346, 0.995352,
- 0.995357, 0.995363, 0.995369, 0.995374, 0.99538, 0.995385, 0.995391,
- 0.995396, 0.995402, 0.995407, 0.995413, 0.995418, 0.995424, 0.995429,
- 0.995435, 0.99544, 0.995445, 0.995451, 0.995456, 0.995462, 0.995467,
- 0.995472, 0.995478, 0.995483, 0.995488, 0.995493, 0.995499, 0.995504,
- 0.995509, 0.995515, 0.99552, 0.995525, 0.99553, 0.995535, 0.995541, 0.995546,
- 0.995551, 0.995556, 0.995561, 0.995566, 0.995571, 0.995577, 0.995582,
- 0.995587, 0.995592, 0.995597, 0.995602, 0.995607, 0.995612, 0.995617,
- 0.995622, 0.995627, 0.995632, 0.995637, 0.995642, 0.995647, 0.995652,
- 0.995657, 0.995661, 0.995666, 0.995671, 0.995676, 0.995681, 0.995686,
- 0.995691, 0.995695, 0.9957, 0.995705, 0.99571, 0.995715, 0.995719, 0.995724,
- 0.995729, 0.995734, 0.995738, 0.995743, 0.995748, 0.995753, 0.995757,
- 0.995762, 0.995767, 0.995771, 0.995776, 0.995781, 0.995785, 0.99579,
- 0.995794, 0.995799, 0.995804, 0.995808, 0.995813, 0.995817, 0.995822,
- 0.995826, 0.995831, 0.995835, 0.99584, 0.995844, 0.995849, 0.995853,
- 0.995858, 0.995862, 0.995867, 0.995871, 0.995876, 0.99588, 0.995885,
- 0.995889, 0.995893, 0.995898, 0.995902, 0.995906, 0.995911, 0.995915,
- 0.99592, 0.995924, 0.995928, 0.995932, 0.995937, 0.995941, 0.995945, 0.99595,
- 0.995954, 0.995958, 0.995962, 0.995967, 0.995971, 0.995975, 0.995979,
- 0.995984, 0.995988, 0.995992, 0.995996, 0.996, 0.996004, 0.996009, 0.996013,
- 0.996017, 0.996021, 0.996025, 0.996029, 0.996033, 0.996037, 0.996041,
- 0.996046, 0.99605, 0.996054, 0.996058, 0.996062, 0.996066, 0.99607, 0.996074,
- 0.996078, 0.996082, 0.996086, 0.99609, 0.996094, 0.996098, 0.996102,
- 0.996106, 0.99611, 0.996114, 0.996117, 0.996121, 0.996125, 0.996129,
- 0.996133, 0.996137, 0.996141, 0.996145, 0.996149, 0.996152, 0.996156,
- 0.99616, 0.996164]
- # Run-time configuration parameters (can be set with command-line options)
- $rerun=1
- $inner=3
- $warmup=1
- $outer=4
- $includeSunSpider=true
- $includeV8=true
- $includeKraken=true
- $measureGC=false
- $benchmarkPattern=nil
- $verbosity=0
- $timeMode=:preciseTime
- $forceVMKind=nil
- $brief=false
- $silent=false
- $remoteHosts=[]
- $alsoLocal=false
- $sshOptions=[]
- $vms = []
- $needToCopyVMs = false
- $dontCopyVMs = false
- $prepare = true
- $run = true
- $analyze = []
- # Helpful functions and classes
- def smallUsage
- puts "Use the --help option to get basic usage information."
- exit 1
- end
- def usage
- puts "bencher [options] <vm1> [<vm2> ...]"
- puts
- puts "Runs one or more JavaScript runtimes against SunSpider, V8, and/or Kraken"
- puts "benchmarks, and reports detailed statistics. What makes bencher special is"
- puts "that each benchmark/VM configuration is run in a single VM invocation, and"
- puts "the invocations are run in random order. This minimizes systematics due to"
- puts "one benchmark polluting the running time of another. The fine-grained"
- puts "interleaving of VM invocations further minimizes systematics due to changes in"
- puts "the performance or behavior of your machine."
- puts
- puts "Bencher is highly configurable. You can compare as many VMs as you like. You"
- puts "can change the amount of warm-up iterations, number of iterations executed per"
- puts "VM invocation, and the number of VM invocations per benchmark. By default,"
- puts "SunSpider, VM, and Kraken are all run; but you can run any combination of these"
- puts "suites."
- puts
- puts "The <vm> should be either a path to a JavaScript runtime executable (such as"
- puts "jsc), or a string of the form <name>:<path>, where the <path> is the path to"
- puts "the executable and <name> is the name that you would like to give the"
- puts "configuration for the purposeof reporting. If no name is given, a generic name"
- puts "of the form Conf#<n> will be ascribed to the configuration automatically."
- puts
- puts "Options:"
- puts "--rerun <n> Set the number of iterations of the benchmark that"
- puts " contribute to the measured run time. Default is #{$rerun}."
- puts "--inner <n> Set the number of inner (per-runtime-invocation)"
- puts " iterations. Default is #{$inner}."
- puts "--outer <n> Set the number of runtime invocations for each benchmark."
- puts " Default is #{$outer}."
- puts "--warmup <n> Set the number of warm-up runs per invocation. Default"
- puts " is #{$warmup}."
- puts "--timing-mode Set the way that bencher measures time. Possible values"
- puts " are 'preciseTime' and 'date'. Default is 'preciseTime'."
- puts "--force-vm-kind Turn off auto-detection of VM kind, and assume that it is"
- puts " the one specified. Valid arguments are 'jsc' or"
- puts " 'DumpRenderTree'."
- puts "--force-vm-copy Force VM builds to be copied to bencher's working directory."
- puts " This may reduce pathologies resulting from path names."
- puts "--dont-copy-vms Don't copy VMs even when doing a remote benchmarking run;"
- puts " instead assume that they are already there."
- puts "--v8-only Only run V8."
- puts "--sunspider-only Only run SunSpider."
- puts "--kraken-only Only run Kraken."
- puts "--exclude-v8 Exclude V8 (only run SunSpider and Kraken)."
- puts "--exclude-sunspider Exclude SunSpider (only run V8 and Kraken)."
- puts "--exclude-kraken Exclude Kraken (only run SunSpider and V8)."
- puts "--benchmarks Only run benchmarks matching the given regular expression."
- puts "--measure-gc Turn off manual calls to gc(), so that GC time is measured."
- puts " Works best with large values of --inner. You can also say"
- puts " --measure-gc <conf>, which turns this on for one"
- puts " configuration only."
- puts "--verbose or -v Print more stuff."
- puts "--brief Print only the final result for each VM."
- puts "--silent Don't print progress. This might slightly reduce some"
- puts " performance perturbation."
- puts "--remote <sshhosts> Performance performance measurements remotely, on the given"
- puts " SSH host(s). Easiest way to use this is to specify the SSH"
- puts " user@host string. However, you can also supply a comma-"
- puts " separated list of SSH hosts. Alternatively, you can use this"
- puts " option multiple times to specify multiple hosts. This"
- puts " automatically copies the WebKit release builds of the VMs"
- puts " you specified to all of the hosts."
- puts "--ssh-options Pass additional options to SSH."
- puts "--local Also do a local benchmark run even when doing --remote."
- puts "--prepare-only Only prepare the bencher runscript (a shell script that"
- puts " invokes the VMs to run benchmarks) but don't run it."
- puts "--analyze Only read the output of the runscript but don't do anything"
- puts " else. This requires passing the same arguments to bencher"
- puts " that you passed when running --prepare-only."
- puts "--help or -h Display this message."
- puts
- puts "Example:"
- puts "bencher TipOfTree:/Volumes/Data/pizlo/OpenSource/WebKitBuild/Release/jsc MyChanges:/Volumes/Data/pizlo/secondary/OpenSource/WebKitBuild/Release/jsc"
- exit 1
- end
- def fail(reason)
- if reason.respond_to? :backtrace
- puts "FAILED: #{reason}"
- puts "Stack trace:"
- puts reason.backtrace.join("\n")
- else
- puts "FAILED: #{reason}"
- end
- smallUsage
- end
- def quickFail(r1,r2)
- $stderr.puts "#{$0}: #{r1}"
- puts
- fail(r2)
- end
- def intArg(argName,arg,min,max)
- result=arg.to_i
- unless result.to_s == arg
- quickFail("Expected an integer value for #{argName}, but got #{arg}.",
- "Invalid argument for command-line option")
- end
- if min and result<min
- quickFail("Argument for #{argName} cannot be smaller than #{min}.",
- "Invalid argument for command-line option")
- end
- if max and result>max
- quickFail("Argument for #{argName} cannot be greater than #{max}.",
- "Invalid argument for command-line option")
- end
- result
- end
- def computeMean(array)
- sum=0.0
- array.each {
- | value |
- sum += value
- }
- sum/array.length
- end
- def computeGeometricMean(array)
- mult=1.0
- array.each {
- | value |
- mult*=value
- }
- mult**(1.0/array.length)
- end
- def computeHarmonicMean(array)
- 1.0 / computeMean(array.collect{ | value | 1.0 / value })
- end
- def computeStdDev(array)
- case array.length
- when 0
- 0.0/0.0
- when 1
- 0.0
- else
- begin
- mean=computeMean(array)
- sum=0.0
- array.each {
- | value |
- sum += (value-mean)**2
- }
- Math.sqrt(sum/(array.length-1))
- rescue
- 0.0/0.0
- end
- end
- end
- class Array
- def shuffle!
- size.downto(1) { |n| push delete_at(rand(n)) }
- self
- end
- end
- def inverseBetaRegularized(n)
- IBR_LOOKUP[n-1]
- end
- def numToStr(num)
- "%.4f"%(num.to_f)
- end
-
- class NoChange
- attr_reader :amountFaster
-
- def initialize(amountFaster)
- @amountFaster = amountFaster
- end
-
- def shortForm
- " "
- end
-
- def longForm
- " might be #{numToStr(@amountFaster)}x faster"
- end
-
- def to_s
- if @amountFaster < 1.01
- ""
- else
- longForm
- end
- end
- end
- class Faster
- attr_reader :amountFaster
-
- def initialize(amountFaster)
- @amountFaster = amountFaster
- end
-
- def shortForm
- "^"
- end
-
- def longForm
- "^ definitely #{numToStr(@amountFaster)}x faster"
- end
-
- def to_s
- longForm
- end
- end
- class Slower
- attr_reader :amountSlower
-
- def initialize(amountSlower)
- @amountSlower = amountSlower
- end
-
- def shortForm
- "!"
- end
-
- def longForm
- "! definitely #{numToStr(@amountSlower)}x slower"
- end
-
- def to_s
- longForm
- end
- end
- class MayBeSlower
- attr_reader :amountSlower
-
- def initialize(amountSlower)
- @amountSlower = amountSlower
- end
-
- def shortForm
- "?"
- end
-
- def longForm
- "? might be #{numToStr(@amountSlower)}x slower"
- end
-
- def to_s
- if @amountSlower < 1.01
- "?"
- else
- longForm
- end
- end
- end
- class Stats
- def initialize
- @array = []
- end
-
- def add(value)
- if value.is_a? Stats
- add(value.array)
- elsif value.respond_to? :each
- value.each {
- | v |
- add(v)
- }
- else
- @array << value.to_f
- end
- end
-
- def array
- @array
- end
-
- def sum
- result=0
- @array.each {
- | value |
- result += value
- }
- result
- end
-
- def min
- @array.min
- end
-
- def max
- @array.max
- end
-
- def size
- @array.length
- end
-
- def mean
- computeMean(array)
- end
-
- def arithmeticMean
- mean
- end
-
- def stdDev
- computeStdDev(array)
- end
- def stdErr
- stdDev/Math.sqrt(size)
- end
-
- # Computes a 95% Student's t distribution confidence interval
- def confInt
- if size < 2
- 0.0/0.0
- else
- raise if size > 1000
- Math.sqrt(size-1.0)*stdErr*Math.sqrt(-1.0+1.0/inverseBetaRegularized(size-1))
- end
- end
-
- def lower
- mean-confInt
- end
-
- def upper
- mean+confInt
- end
-
- def geometricMean
- computeGeometricMean(array)
- end
-
- def harmonicMean
- computeHarmonicMean(array)
- end
-
- def compareTo(other)
- if upper < other.lower
- Faster.new(other.mean/mean)
- elsif lower > other.upper
- Slower.new(mean/other.mean)
- elsif mean > other.mean
- MayBeSlower.new(mean/other.mean)
- else
- NoChange.new(other.mean/mean)
- end
- end
-
- def to_s
- "size = #{size}, mean = #{mean}, stdDev = #{stdDev}, stdErr = #{stdErr}, confInt = #{confInt}"
- end
- end
- def doublePuts(out1,out2,msg)
- out1.puts "#{out2.path}: #{msg}" if $verbosity>=3
- out2.puts msg
- end
- class Benchfile < File
- @@counter = 0
-
- attr_reader :filename, :basename
-
- def initialize(name)
- @basename, @filename = Benchfile.uniqueFilename(name)
- super(@filename, "w")
- end
-
- def self.uniqueFilename(name)
- if name.is_a? Array
- basename = name[0] + @@counter.to_s + name[1]
- else
- basename = name + @@counter.to_s
- end
- filename = BENCH_DATA_PATH + "/" + basename
- @@counter += 1
- raise "Benchfile #{filename} already exists" if FileTest.exist?(filename)
- [basename, filename]
- end
-
- def self.create(name)
- file = Benchfile.new(name)
- yield file
- file.close
- file.basename
- end
- end
- $dataFiles={}
- def ensureFile(key, filename)
- unless $dataFiles[key]
- $dataFiles[key] = Benchfile.create(key) {
- | outp |
- doublePuts($stderr,outp,IO::read(filename))
- }
- end
- $dataFiles[key]
- end
-
- def emitBenchRunCodeFile(name, plan, benchDataPath, benchPath)
- case plan.vm.vmType
- when :jsc
- Benchfile.create("bencher") {
- | file |
- case $timeMode
- when :preciseTime
- doublePuts($stderr,file,"function __bencher_curTimeMS() {")
- doublePuts($stderr,file," return preciseTime()*1000")
- doublePuts($stderr,file,"}")
- when :date
- doublePuts($stderr,file,"function __bencher_curTimeMS() {")
- doublePuts($stderr,file," return Date.now()")
- doublePuts($stderr,file,"}")
- else
- raise
- end
-
- if benchDataPath
- doublePuts($stderr,file,"load(#{benchDataPath.inspect});")
- doublePuts($stderr,file,"gc();")
- doublePuts($stderr,file,"for (var __bencher_index = 0; __bencher_index < #{$warmup+$inner}; ++__bencher_index) {")
- doublePuts($stderr,file," before = __bencher_curTimeMS();")
- $rerun.times {
- doublePuts($stderr,file," load(#{benchPath.inspect});")
- }
- doublePuts($stderr,file," after = __bencher_curTimeMS();")
- doublePuts($stderr,file," if (__bencher_index >= #{$warmup}) print(\"#{name}: #{plan.vm}: #{plan.iteration}: \" + (__bencher_index - #{$warmup}) + \": Time: \"+(after-before));");
- doublePuts($stderr,file," gc();") unless plan.vm.shouldMeasureGC
- doublePuts($stderr,file,"}")
- else
- doublePuts($stderr,file,"function __bencher_run(__bencher_what) {")
- doublePuts($stderr,file," var __bencher_before = __bencher_curTimeMS();")
- $rerun.times {
- doublePuts($stderr,file," run(__bencher_what);")
- }
- doublePuts($stderr,file," var __bencher_after = __bencher_curTimeMS();")
- doublePuts($stderr,file," return __bencher_after - __bencher_before;")
- doublePuts($stderr,file,"}")
- $warmup.times {
- doublePuts($stderr,file,"__bencher_run(#{benchPath.inspect})")
- doublePuts($stderr,file,"gc();") unless plan.vm.shouldMeasureGC
- }
- $inner.times {
- | innerIndex |
- doublePuts($stderr,file,"print(\"#{name}: #{plan.vm}: #{plan.iteration}: #{innerIndex}: Time: \"+__bencher_run(#{benchPath.inspect}));")
- doublePuts($stderr,file,"gc();") unless plan.vm.shouldMeasureGC
- }
- end
- }
- when :dumpRenderTree
- mainCode = Benchfile.create("bencher") {
- | file |
- doublePuts($stderr,file,"__bencher_count = 0;")
- doublePuts($stderr,file,"function __bencher_doNext(result) {")
- doublePuts($stderr,file," if (__bencher_count >= #{$warmup})")
- doublePuts($stderr,file," debug(\"#{name}: #{plan.vm}: #{plan.iteration}: \" + (__bencher_count - #{$warmup}) + \": Time: \" + result);")
- doublePuts($stderr,file," __bencher_count++;")
- doublePuts($stderr,file," if (__bencher_count < #{$inner+$warmup})")
- doublePuts($stderr,file," __bencher_runImpl(__bencher_doNext);")
- doublePuts($stderr,file," else")
- doublePuts($stderr,file," quit();")
- doublePuts($stderr,file,"}")
- doublePuts($stderr,file,"__bencher_runImpl(__bencher_doNext);")
- }
-
- cssCode = Benchfile.create("bencher-css") {
- | file |
- doublePuts($stderr,file,".pass {\n font-weight: bold;\n color: green;\n}\n.fail {\n font-weight: bold;\n color: red;\n}\n\#console {\n white-space: pre-wrap;\n font-family: monospace;\n}")
- }
-
- preCode = Benchfile.create("bencher-pre") {
- | file |
- doublePuts($stderr,file,"if (window.testRunner) {")
- doublePuts($stderr,file," testRunner.dumpAsText(window.enablePixelTesting);")
- doublePuts($stderr,file," testRunner.waitUntilDone();")
- doublePuts($stderr,file,"}")
- doublePuts($stderr,file,"")
- doublePuts($stderr,file,"function debug(msg)")
- doublePuts($stderr,file,"{")
- doublePuts($stderr,file," var span = document.createElement(\"span\");")
- doublePuts($stderr,file," document.getElementById(\"console\").appendChild(span); // insert it first so XHTML knows the namespace")
- doublePuts($stderr,file," span.innerHTML = msg + '<br />';")
- doublePuts($stderr,file,"}")
- doublePuts($stderr,file,"")
- doublePuts($stderr,file,"function quit() {")
- doublePuts($stderr,file," testRunner.notifyDone();")
- doublePuts($stderr,file,"}")
- doublePuts($stderr,file,"")
- doublePuts($stderr,file,"__bencher_continuation=null;")
- doublePuts($stderr,file,"")
- doublePuts($stderr,file,"function reportResult(result) {")
- doublePuts($stderr,file," __bencher_continuation(result);")
- doublePuts($stderr,file,"}")
- doublePuts($stderr,file,"")
- doublePuts($stderr,file,"function __bencher_runImpl(continuation) {")
- doublePuts($stderr,file," function doit() {")
- doublePuts($stderr,file," document.getElementById(\"frameparent\").innerHTML = \"\";")
- doublePuts($stderr,file," document.getElementById(\"frameparent\").innerHTML = \"<iframe id='testframe'>\";")
- doublePuts($stderr,file," var testFrame = document.getElementById(\"testframe\");")
- doublePuts($stderr,file," testFrame.contentDocument.open();")
- doublePuts($stderr,file," testFrame.contentDocument.write(\"<!DOCTYPE html>\\n<head></head><body><div id=\\\"console\\\"></div>\");")
- if benchDataPath
- doublePuts($stderr,file," testFrame.contentDocument.write(\"<script src=\\\"#{benchDataPath}\\\"></script>\");")
- end
- doublePuts($stderr,file," testFrame.contentDocument.write(\"<script type=\\\"text/javascript\\\">__bencher_before = Date.now();</script><script src=\\\"#{benchPath}\\\"></script><script type=\\\"text/javascript\\\">window.parent.reportResult(Date.now() - __bencher_before);</script></body></html>\");")
- doublePuts($stderr,file," testFrame.contentDocument.close();")
- doublePuts($stderr,file," }")
- doublePuts($stderr,file," __bencher_continuation = continuation;")
- doublePuts($stderr,file," window.setTimeout(doit, 10);")
- doublePuts($stderr,file,"}")
- }
- Benchfile.create(["bencher-htmldoc",".html"]) {
- | file |
- doublePuts($stderr,file,"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n<html><head><link rel=\"stylesheet\" href=\"#{cssCode}\"><script src=\"#{preCode}\"></script></head><body><div id=\"console\"></div><div id=\"frameparent\"></div><script src=\"#{mainCode}\"></script></body></html>")
- }
- else
- raise
- end
- end
- def emitBenchRunCode(name, plan, benchDataPath, benchPath)
- plan.vm.emitRunCode(emitBenchRunCodeFile(name, plan, benchDataPath, benchPath))
- end
- def planForDescription(plans, benchFullname, vmName, iteration)
- raise unless benchFullname =~ /\//
- suiteName = $~.pre_match
- benchName = $~.post_match
- result = plans.select{|v| v.suite.name == suiteName and v.benchmark.name == benchName and v.vm.name == vmName and v.iteration == iteration}
- raise unless result.size == 1
- result[0]
- end
- class ParsedResult
- attr_reader :plan, :innerIndex, :time
-
- def initialize(plan, innerIndex, time)
- @plan = plan
- @innerIndex = innerIndex
- @time = time
-
- raise unless @plan.is_a? BenchPlan
- raise unless @innerIndex.is_a? Integer
- raise unless @time.is_a? Numeric
- end
-
- def benchmark
- plan.benchmark
- end
-
- def suite
- plan.suite
- end
-
- def vm
- plan.vm
- end
-
- def outerIndex
- plan.iteration
- end
-
- def self.parse(plans, string)
- if string =~ /([a-zA-Z0-9\/-]+): ([a-zA-Z0-9_# ]+): ([0-9]+): ([0-9]+): Time: /
- benchFullname = $1
- vmName = $2
- outerIndex = $3.to_i
- innerIndex = $4.to_i
- time = $~.post_match.to_f
- ParsedResult.new(planForDescription(plans, benchFullname, vmName, outerIndex), innerIndex, time)
- else
- nil
- end
- end
- end
- class VM
- def initialize(origPath, name, nameKind, svnRevision)
- @origPath = origPath.to_s
- @path = origPath.to_s
- @name = name
- @nameKind = nameKind
-
- if $forceVMKind
- @vmType = $forceVMKind
- else
- if @origPath =~ /DumpRenderTree$/
- @vmType = :dumpRenderTree
- else
- @vmType = :jsc
- end
- end
-
- @svnRevision = svnRevision
-
- # Try to detect information about the VM.
- if path =~ /\/WebKitBuild\/Release\/([a-zA-Z]+)$/
- @checkoutPath = $~.pre_match
- # FIXME: Use some variant of this:
- # <bdash> def retrieve_revision
- # <bdash> `perl -I#{@path}/Tools/Scripts -MVCSUtils -e 'print svnRevisionForDirectory("#{@path}");'`.to_i
- # <bdash> end
- unless @svnRevision
- begin
- Dir.chdir(@checkoutPath) {
- $stderr.puts ">> cd #{@checkoutPath} && svn info" if $verbosity>=2
- IO.popen("svn info", "r") {
- | inp |
- inp.each_line {
- | line |
- if line =~ /Revision: ([0-9]+)/
- @svnRevision = $1
- end
- }
- }
- }
- unless @svnRevision
- $stderr.puts "Warning: running svn info for #{name} silently failed."
- end
- rescue => e
- # Failed to detect svn revision.
- $stderr.puts "Warning: could not get svn revision information for #{name}: #{e}"
- end
- end
- else
- $stderr.puts "Warning: could not identify checkout location for #{name}"
- end
-
- if @path =~ /\/Release\/([a-zA-Z]+)$/
- @libPath, @relativeBinPath = $~.pre_match+"/Release", "./#{$1}"
- elsif @path =~ /\/Contents\/Resources\/([a-zA-Z]+)$/
- @libPath = $~.pre_match
- elsif @path =~ /\/JavaScriptCore.framework\/Resources\/([a-zA-Z]+)$/
- @libPath, @relativeBinPath = $~.pre_match, $&[1..-1]
- end
- end
-
- def canCopyIntoBenchPath
- if @libPath and @relativeBinPath
- true
- else
- false
- end
- end
-
- def copyIntoBenchPath
- raise unless canCopyIntoBenchPath
- basename, filename = Benchfile.uniqueFilename("vm")
- raise unless Dir.mkdir(filename)
- cmd = "cp -a #{@libPath.inspect}/* #{filename.inspect}"
- $stderr.puts ">> #{cmd}" if $verbosity>=2
- raise unless system(cmd)
- @path = "#{basename}/#{@relativeBinPath}"
- @libPath = basename
- end
-
- def to_s
- @name
- end
-
- def name
- @name
- end
-
- def shouldMeasureGC
- $measureGC == true or ($measureGC == name)
- end
-
- def origPath
- @origPath
- end
-
- def path
- @path
- end
-
- def nameKind
- @nameKind
- end
-
- def vmType
- @vmType
- end
-
- def checkoutPath
- @checkoutPath
- end
-
- def svnRevision
- @svnRevision
- end
-
- def printFunction
- case @vmType
- when :jsc
- "print"
- when :dumpRenderTree
- "debug"
- else
- raise @vmType
- end
- end
-
- def emitRunCode(fileToRun)
- myLibPath = @libPath
- myLibPath = "" unless myLibPath
- $script.puts "export DYLD_LIBRARY_PATH=#{myLibPath.to_s.inspect}"
- $script.puts "export DYLD_FRAMEWORK_PATH=#{myLibPath.to_s.inspect}"
- $script.puts "#{path} #{fileToRun}"
- end
- end
- class StatsAccumulator
- def initialize
- @stats = []
- ($outer*$inner).times {
- @stats << Stats.new
- }
- end
-
- def statsForIteration(outerIteration, innerIteration)
- @stats[outerIteration*$inner + innerIteration]
- end
-
- def stats
- result = Stats.new
- @stats.each {
- | stat |
- result.add(yield stat)
- }
- result
- end
-
- def geometricMeanStats
- stats {
- | stat |
- stat.geometricMean
- }
- end
-
- def arithmeticMeanStats
- stats {
- | stat |
- stat.arithmeticMean
- }
- end
- end
- module Benchmark
- attr_accessor :benchmarkSuite
- attr_reader :name
-
- def fullname
- benchmarkSuite.name + "/" + name
- end
-
- def to_s
- fullname
- end
- end
- class SunSpiderBenchmark
- include Benchmark
-
- def initialize(name)
- @name = name
- end
-
- def emitRunCode(plan)
- emitBenchRunCode(fullname, plan, nil, ensureFile("SunSpider-#{@name}", "#{SUNSPIDER_PATH}/#{@name}.js"))
- end
- end
- class V8Benchmark
- include Benchmark
-
- def initialize(name)
- @name = name
- end
-
- def emitRunCode(plan)
- emitBenchRunCode(fullname, plan, nil, ensureFile("V8-#{@name}", "#{V8_PATH}/v8-#{@name}.js"))
- end
- end
- class KrakenBenchmark
- include Benchmark
-
- def initialize(name)
- @name = name
- end
-
- def emitRunCode(plan)
- emitBenchRunCode(fullname, plan, ensureFile("KrakenData-#{@name}", "#{KRAKEN_PATH}/#{@name}-data.js"), ensureFile("Kraken-#{@name}", "#{KRAKEN_PATH}/#{@name}.js"))
- end
- end
- class BenchmarkSuite
- def initialize(name, path, preferredMean)
- @name = name
- @path = path
- @preferredMean = preferredMean
- @benchmarks = []
- end
-
- def name
- @name
- end
-
- def to_s
- @name
- end
-
- def path
- @path
- end
-
- def add(benchmark)
- if not $benchmarkPattern or "#{@name}/#{benchmark.name}" =~ $benchmarkPattern
- benchmark.benchmarkSuite = self
- @benchmarks << benchmark
- end
- end
-
- def benchmarks
- @benchmarks
- end
-
- def benchmarkForName(name)
- result = @benchmarks.select{|v| v.name == name}
- raise unless result.length == 1
- result[0]
- end
-
- def empty?
- @benchmarks.empty?
- end
-
- def retain_if
- @benchmarks.delete_if {
- | benchmark |
- not yield benchmark
- }
- end
-
- def preferredMean
- @preferredMean
- end
-
- def computeMean(stat)
- stat.send @preferredMean
- end
- end
- class BenchRunPlan
- def initialize(benchmark, vm, iteration)
- @benchmark = benchmark
- @vm = vm
- @iteration = iteration
- end
-
- def benchmark
- @benchmark
- end
-
- def suite
- @benchmark.benchmarkSuite
- end
-
- def vm
- @vm
- end
-
- def iteration
- @iteration
- end
-
- def emitRunCode
- @benchmark.emitRunCode(self)
- end
- end
- class BenchmarkOnVM
- def initialize(benchmark, suiteOnVM)
- @benchmark = benchmark
- @suiteOnVM = suiteOnVM
- @stats = Stats.new
- end
-
- def to_s
- "#{@benchmark} on #{@suiteOnVM.vm}"
- end
-
- def benchmark
- @benchmark
- end
-
- def vm
- @suiteOnVM.vm
- end
-
- def vmStats
- @suiteOnVM.vmStats
- end
-
- def suite
- @benchmark.benchmarkSuite
- end
-
- def suiteOnVM
- @suiteOnVM
- end
-
- def stats
- @stats
- end
-
- def parseResult(result)
- raise "VM mismatch; I've got #{vm} and they've got #{result.vm}" unless result.vm == vm
- raise unless result.benchmark == @benchmark
- @stats.add(result.time)
- end
- end
- class SuiteOnVM < StatsAccumulator
- def initialize(vm, vmStats, suite)
- super()
- @vm = vm
- @vmStats = vmStats
- @suite = suite
-
- raise unless @vm.is_a? VM
- raise unless @vmStats.is_a? StatsAccumulator
- raise unless @suite.is_a? BenchmarkSuite
- end
-
- def to_s
- "#{@suite} on #{@vm}"
- end
-
- def suite
- @suite
- end
-
- def vm
- @vm
- end
-
- def vmStats
- raise unless @vmStats
- @vmStats
- end
- end
- class BenchPlan
- def initialize(benchmarkOnVM, iteration)
- @benchmarkOnVM = benchmarkOnVM
- @iteration = iteration
- end
-
- def to_s
- "#{@benchmarkOnVM} \##{@iteration+1}"
- end
-
- def benchmarkOnVM
- @benchmarkOnVM
- end
-
- def benchmark
- @benchmarkOnVM.benchmark
- end
-
- def suite
- @benchmarkOnVM.suite
- end
-
- def vm
- @benchmarkOnVM.vm
- end
-
- def iteration
- @iteration
- end
-
- def parseResult(result)
- raise unless result.plan == self
- @benchmarkOnVM.parseResult(result)
- @benchmarkOnVM.vmStats.statsForIteration(@iteration, result.innerIndex).add(result.time)
- @benchmarkOnVM.suiteOnVM.statsForIteration(@iteration, result.innerIndex).add(result.time)
- end
- end
- def lpad(str,chars)
- if str.length>chars
- str
- else
- "%#{chars}s"%(str)
- end
- end
- def rpad(str,chars)
- while str.length<chars
- str+=" "
- end
- str
- end
- def center(str,chars)
- while str.length<chars
- str+=" "
- if str.length<chars
- str=" "+str
- end
- end
- str
- end
- def statsToStr(stats)
- if $inner*$outer == 1
- string = numToStr(stats.mean)
- raise unless string =~ /\./
- left = $~.pre_match
- right = $~.post_match
- lpad(left,12)+"."+rpad(right,9)
- else
- lpad(numToStr(stats.mean),11)+"+-"+rpad(numToStr(stats.confInt),9)
- end
- end
- def plural(num)
- if num == 1
- ""
- else
- "s"
- end
- end
- def wrap(str, columns)
- array = str.split
- result = ""
- curLine = array.shift
- array.each {
- | curStr |
- if (curLine + " " + curStr).size > columns
- result += curLine + "\n"
- curLine = curStr
- else
- curLine += " " + curStr
- end
- }
- result + curLine + "\n"
- end
-
- def runAndGetResults
- results = nil
- Dir.chdir(BENCH_DATA_PATH) {
- IO.popen("sh ./runscript", "r") {
- | inp |
- results = inp.read
- }
- raise "Script did not complete correctly: #{$?}" unless $?.success?
- }
- raise unless results
- results
- end
- def parseAndDisplayResults(results)
- vmStatses = []
- $vms.each {
- vmStatses << StatsAccumulator.new
- }
-
- suitesOnVMs = []
- suitesOnVMsForSuite = {}
- $suites.each {
- | suite |
- suitesOnVMsForSuite[suite] = []
- }
- suitesOnVMsForVM = {}
- $vms.each {
- | vm |
- suitesOnVMsForVM[vm] = []
- }
-
- benchmarksOnVMs = []
- benchmarksOnVMsForBenchmark = {}
- $benchmarks.each {
- | benchmark |
- benchmarksOnVMsForBenchmark[benchmark] = []
- }
-
- $vms.each_with_index {
- | vm, vmIndex |
- vmStats = vmStatses[vmIndex]
- $suites.each {
- | suite |
- suiteOnVM = SuiteOnVM.new(vm, vmStats, suite)
- suitesOnVMs << suiteOnVM
- suitesOnVMsForSuite[suite] << suiteOnVM
- suitesOnVMsForVM[vm] << suiteOnVM
- suite.benchmarks.each {
- | benchmark |
- benchmarkOnVM = BenchmarkOnVM.new(benchmark, suiteOnVM)
- benchmarksOnVMs << benchmarkOnVM
- benchmarksOnVMsForBenchmark[benchmark] << benchmarkOnVM
- }
- }
- }
-
- plans = []
- benchmarksOnVMs.each {
- | benchmarkOnVM |
- $outer.times {
- | iteration |
- plans << BenchPlan.new(benchmarkOnVM, iteration)
- }
- }
- hostname = nil
- hwmodel = nil
- results.each_line {
- | line |
- line.chomp!
- if line =~ /HOSTNAME:([^.]+)/
- hostname = $1
- elsif line =~ /HARDWARE:hw\.model: /
- hwmodel = $~.post_match.chomp
- else
- result = ParsedResult.parse(plans, line.chomp)
- if result
- result.plan.parseResult(result)
- end
- end
- }
-
- # Compute the geomean of the preferred means of results on a SuiteOnVM
- overallResults = []
- $vms.each {
- | vm |
- result = Stats.new
- $outer.times {
- | outerIndex |
- $inner.times {
- | innerIndex |
- curResult = Stats.new
- suitesOnVMsForVM[vm].each {
- | suiteOnVM |
- # For a given iteration, suite, and VM, compute the suite's preferred mean
- # over the data collected for all benchmarks in that suite. We'll have one
- # sample per benchmark. For example on V8 this will be the geomean of 1
- # sample for crypto, 1 sample for deltablue, and so on, and 1 sample for
- # splay.
- curResult.add(suiteOnVM.suite.computeMean(suiteOnVM.statsForIteration(outerIndex, innerIndex)))
- }
-
- # curResult now holds 1 sample for each of the means computed in the above
- # loop. Compute the geomean over this, and store it.
- result.add(curResult.geometricMean)
- }
- }
- # $overallResults will have a Stats for each VM. That Stats object will hold
- # $inner*$outer geomeans, allowing us to compute the arithmetic mean and
- # confidence interval of the geomeans of preferred means. Convoluted, but
- # useful and probably sound.
- overallResults << result
- }
-
- if $verbosity >= 2
- benchmarksOnVMs.each {
- | benchmarkOnVM |
- $stderr.puts "#{benchmarkOnVM}: #{benchmarkOnVM.stats}"
- }
-
- $vms.each_with_index {
- | vm, vmIndex |
- vmStats = vmStatses[vmIndex]
- $stderr.puts "#{vm} (arithmeticMean): #{vmStats.arithmeticMeanStats}"
- $stderr.puts "#{vm} (geometricMean): #{vmStats.geometricMeanStats}"
- }
- end
- reportName =
- (if ($vms.collect {
- | vm |
- vm.nameKind
- }.index :auto)
- ""
- else
- $vms.collect {
- | vm |
- vm.to_s
- }.join("_") + "_"
- end) +
- ($suites.collect {
- | suite |
- suite.to_s
- }.join("")) + "_" +
- (if hostname
- hostname + "_"
- else
- ""
- end)+
- (begin
- time = Time.now
- "%04d%02d%02d_%02d%02d" %
- [ time.year, time.month, time.day,
- time.hour, time.min ]
- end) +
- "_benchReport.txt"
- unless $brief
- puts "Generating benchmark report at #{reportName}"
- end
-
- outp = $stdout
- begin
- outp = File.open(reportName,"w")
- rescue => e
- $stderr.puts "Error: could not save report to #{reportName}: #{e}"
- $stderr.puts
- end
-
- def createVMsString
- result = ""
- result += " " if $suites.size > 1
- result += rpad("", $benchpad)
- result += " "
- $vms.size.times {
- | index |
- if index != 0
- result += " "+NoChange.new(0).shortForm
- end
- result += lpad(center($vms[index].name, 9+9+2), 11+9+2)
- }
- result += " "
- if $vms.size >= 3
- result += center("#{$vms[-1].name} v. #{$vms[0].name}",26)
- elsif $vms.size >= 2
- result += " "*26
- end
- result
- end
-
- columns = [createVMsString.size, 78].max
-
- outp.print "Benchmark report for "
- if $suites.size == 1
- outp.print $suites[0].to_s
- elsif $suites.size == 2
- outp.print "#{$suites[0]} and #{$suites[1]}"
- else
- outp.print "#{$suites[0..-2].join(', ')}, and #{$suites[-1]}"
- end
- if hostname
- outp.print " on #{hostname}"
- end
- if hwmodel
- outp.print " (#{hwmodel})"
- end
- outp.puts "."
- outp.puts
-
- # This looks stupid; revisit later.
- if false
- $suites.each {
- | suite |
- outp.puts "#{suite} at #{suite.path}"
- }
-
- outp.puts
- end
-
- outp.puts "VMs tested:"
- $vms.each {
- | vm |
- outp.print "\"#{vm.name}\" at #{vm.origPath}"
- if vm.svnRevision
- outp.print " (r#{vm.svnRevision})"
- end
- outp.puts
- }
-
- outp.puts
-
- outp.puts wrap("Collected #{$outer*$inner} sample#{plural($outer*$inner)} per benchmark/VM, "+
- "with #{$outer} VM invocation#{plural($outer)} per benchmark."+
- (if $rerun > 1 then (" Ran #{$rerun} benchmark iterations, and measured the "+
- "total time of those iterations, for each sample.")
- else "" end)+
- (if $measureGC == true then (" No manual garbage collection invocations were "+
- "emitted.")
- elsif $measureGC then (" Emitted a call to gc() between sample measurements for "+
- "all VMs except #{$measureGC}.")
- else (" Emitted a call to gc() between sample measurements.") end)+
- (if $warmup == 0 then (" Did not include any warm-up iterations; measurements "+
- "began with the very first iteration.")
- else (" Used #{$warmup*$rerun} benchmark iteration#{plural($warmup*$rerun)} per VM "+
- "invocation for warm-up.") end)+
- (case $timeMode
- when :preciseTime then (" Used the jsc-specific preciseTime() function to get "+
- "microsecond-level timing.")
- when :date then (" Used the portable Date.now() method to get millisecond-"+
- "level timing.")
- else raise end)+
- " Reporting benchmark execution times with 95% confidence "+
- "intervals in milliseconds.",
- columns)
-
- outp.puts
-
- def printVMs(outp)
- outp.puts createVMsString
- end
-
- def summaryStats(outp, accumulators, name, &proc)
- outp.print " " if $suites.size > 1
- outp.print rpad(name, $benchpad)
- outp.print " "
- accumulators.size.times {
- | index |
- if index != 0
- outp.print " "+accumulators[index].stats(&proc).compareTo(accumulators[index-1].stats(&proc)).shortForm
- end
- outp.print statsToStr(accumulators[index].stats(&proc))
- }
- if accumulators.size>=2
- outp.print(" "+accumulators[-1].stats(&proc).compareTo(accumulators[0].stats(&proc)).longForm)
- end
- outp.puts
- end
-
- def meanName(currentMean, preferredMean)
- result = "<#{currentMean}>"
- if "#{currentMean}Mean" == preferredMean.to_s
- result += " *"
- end
- result
- end
-
- def allSummaryStats(outp, accumulators, preferredMean)
- summaryStats(outp, accumulators, meanName("arithmetic", preferredMean)) {
- | stat |
- stat.arithmeticMean
- }
-
- summaryStats(outp, accumulators, meanName("geometric", preferredMean)) {
- | stat |
- stat.geometricMean
- }
-
- summaryStats(outp, accumulators, meanName("harmonic", preferredMean)) {
- | stat |
- stat.harmonicMean
- }
- end
-
- $suites.each {
- | suite |
- printVMs(outp)
- if $suites.size > 1
- outp.puts "#{suite.name}:"
- else
- outp.puts
- end
- suite.benchmarks.each {
- | benchmark |
- outp.print " " if $suites.size > 1
- outp.print rpad(benchmark.name, $benchpad)
- outp.print " "
- myConfigs = benchmarksOnVMsForBenchmark[benchmark]
- myConfigs.size.times {
- | index |
- if index != 0
- outp.print " "+myConfigs[index].stats.compareTo(myConfigs[index-1].stats).shortForm
- end
- outp.print statsToStr(myConfigs[index].stats)
- }
- if $vms.size>=2
- outp.print(" "+myConfigs[-1].stats.compareTo(myConfigs[0].stats).to_s)
- end
- outp.puts
- }
- outp.puts
- allSummaryStats(outp, suitesOnVMsForSuite[suite], suite.preferredMean)
- outp.puts if $suites.size > 1
- }
-
- if $suites.size > 1
- printVMs(outp)
- outp.puts "All benchmarks:"
- allSummaryStats(outp, vmStatses, nil)
-
- outp.puts
- printVMs(outp)
- outp.puts "Geomean of preferred means:"
- outp.print " "
- outp.print rpad("<scaled-result>", $benchpad)
- outp.print " "
- $vms.size.times {
- | index |
- if index != 0
- outp.print " "+overallResults[index].compareTo(overallResults[index-1]).shortForm
- end
- outp.print statsToStr(overallResults[index])
- }
- if overallResults.size>=2
- outp.print(" "+overallResults[-1].compareTo(overallResults[0]).longForm)
- end
- outp.puts
- end
- outp.puts
-
- if outp != $stdout
- outp.close
- end
-
- if outp != $stdout and not $brief
- puts
- File.open(reportName) {
- | inp |
- puts inp.read
- }
- end
-
- if $brief
- puts(overallResults.collect{|stats| stats.mean}.join("\t"))
- puts(overallResults.collect{|stats| stats.confInt}.join("\t"))
- end
-
-
- end
- begin
- $sawBenchOptions = false
-
- def resetBenchOptionsIfNecessary
- unless $sawBenchOptions
- $includeSunSpider = false
- $includeV8 = false
- $includeKraken = false
- $sawBenchOptions = true
- end
- end
-
- GetoptLong.new(['--rerun', GetoptLong::REQUIRED_ARGUMENT],
- ['--inner', GetoptLong::REQUIRED_ARGUMENT],
- ['--outer', GetoptLong::REQUIRED_ARGUMENT],
- ['--warmup', GetoptLong::REQUIRED_ARGUMENT],
- ['--timing-mode', GetoptLong::REQUIRED_ARGUMENT],
- ['--sunspider-only', GetoptLong::NO_ARGUMENT],
- ['--v8-only', GetoptLong::NO_ARGUMENT],
- ['--kraken-only', GetoptLong::NO_ARGUMENT],
- ['--exclude-sunspider', GetoptLong::NO_ARGUMENT],
- ['--exclude-v8', GetoptLong::NO_ARGUMENT],
- ['--exclude-kraken', GetoptLong::NO_ARGUMENT],
- ['--sunspider', GetoptLong::NO_ARGUMENT],
- ['--v8', GetoptLong::NO_ARGUMENT],
- ['--kraken', GetoptLong::NO_ARGUMENT],
- ['--benchmarks', GetoptLong::REQUIRED_ARGUMENT],
- ['--measure-gc', GetoptLong::OPTIONAL_ARGUMENT],
- ['--force-vm-kind', GetoptLong::REQUIRED_ARGUMENT],
- ['--force-vm-copy', GetoptLong::NO_ARGUMENT],
- ['--dont-copy-vms', GetoptLong::NO_ARGUMENT],
- ['--verbose', '-v', GetoptLong::NO_ARGUMENT],
- ['--brief', GetoptLong::NO_ARGUMENT],
- ['--silent', GetoptLong::NO_ARGUMENT],
- ['--remote', GetoptLong::REQUIRED_ARGUMENT],
- ['--local', GetoptLong::NO_ARGUMENT],
- ['--ssh-options', GetoptLong::REQUIRED_ARGUMENT],
- ['--slave', GetoptLong::NO_ARGUMENT],
- ['--prepare-only', GetoptLong::NO_ARGUMENT],
- ['--analyze', GetoptLong::REQUIRED_ARGUMENT],
- ['--vms', GetoptLong::REQUIRED_ARGUMENT],
- ['--help', '-h', GetoptLong::NO_ARGUMENT]).each {
- | opt, arg |
- case opt
- when '--rerun'
- $rerun = intArg(opt,arg,1,nil)
- when '--inner'
- $inner = intArg(opt,arg,1,nil)
- when '--outer'
- $outer = intArg(opt,arg,1,nil)
- when '--warmup'
- $warmup = intArg(opt,arg,0,nil)
- when '--timing-mode'
- if arg.upcase == "PRECISETIME"
- $timeMode = :preciseTime
- elsif arg.upcase == "DATE"
- $timeMode = :date
- elsif arg.upcase == "AUTO"
- $timeMode = :auto
- else
- quickFail("Expected either 'preciseTime', 'date', or 'auto' for --time-mode, but got '#{arg}'.",
- "Invalid argument for command-line option")
- end
- when '--force-vm-kind'
- if arg.upcase == "JSC"
- $forceVMKind = :jsc
- elsif arg.upcase == "DUMPRENDERTREE"
- $forceVMKind = :dumpRenderTree
- elsif arg.upcase == "AUTO"
- $forceVMKind = nil
- else
- quickFail("Expected either 'jsc' or 'DumpRenderTree' for --force-vm-kind, but got '#{arg}'.",
- "Invalid argument for command-line option")
- end
- when '--force-vm-copy'
- $needToCopyVMs = true
- when '--dont-copy-vms'
- $dontCopyVMs = true
- when '--sunspider-only'
- $includeV8 = false
- $includeKraken = false
- when '--v8-only'
- $includeSunSpider = false
- $includeKraken = false
- when '--kraken-only'
- $includeSunSpider = false
- $includeV8 = false
- when '--exclude-sunspider'
- $includeSunSpider = false
- when '--exclude-v8'
- $includeV8 = false
- when '--exclude-kraken'
- $includeKraken = false
- when '--sunspider'
- resetBenchOptionsIfNecessary
- $includeSunSpider = true
- when '--v8'
- resetBenchOptionsIfNecessary
- $includeV8 = true
- when '--kraken'
- resetBenchOptionsIfNecessary
- $includeKraken = true
- when '--benchmarks'
- $benchmarkPattern = Regexp.new(arg)
- when '--measure-gc'
- if arg == ''
- $measureGC = true
- else
- $measureGC = arg
- end
- when '--verbose'
- $verbosity += 1
- when '--brief'
- $brief = true
- when '--silent'
- $silent = true
- when '--remote'
- $remoteHosts += arg.split(',')
- $needToCopyVMs = true
- when '--ssh-options'
- $sshOptions << arg
- when '--local'
- $alsoLocal = true
- when '--prepare-only'
- $run = false
- when '--analyze'
- $prepare = false
- $run = false
- $analyze << arg
- when '--help'
- usage
- else
- raise "bad option: #{opt}"
- end
- }
-
- # If the --dont-copy-vms option was passed, it overrides the --force-vm-copy option.
- if $dontCopyVMs
- $needToCopyVMs = false
- end
-
- SUNSPIDER = BenchmarkSuite.new("SunSpider", SUNSPIDER_PATH, :arithmeticMean)
- ["3d-cube", "3d-morph", "3d-raytrace", "access-binary-trees",
- "access-fannkuch", "access-nbody", "access-nsieve",
- "bitops-3bit-bits-in-byte", "bitops-bits-in-byte", "bitops-bitwise-and",
- "bitops-nsieve-bits", "controlflow-recursive", "crypto-aes",
- "crypto-md5", "crypto-sha1", "date-format-tofte", "date-format-xparb",
- "math-cordic", "math-partial-sums", "math-spectral-norm", "regexp-dna",
- "string-base64", "string-fasta", "string-tagcloud",
- "string-unpack-code", "string-validate-input"].each {
- | name |
- SUNSPIDER.add SunSpiderBenchmark.new(name)
- }
- V8 = BenchmarkSuite.new("V8", V8_PATH, :geometricMean)
- ["crypto", "deltablue", "earley-boyer", "raytrace",
- "regexp", "richards", "splay"].each {
- | name |
- V8.add V8Benchmark.new(name)
- }
- KRAKEN = BenchmarkSuite.new("Kraken", KRAKEN_PATH, :arithmeticMean)
- ["ai-astar", "audio-beat-detection", "audio-dft", "audio-fft",
- "audio-oscillator", "imaging-darkroom", "imaging-desaturate",
- "imaging-gaussian-blur", "json-parse-financial",
- "json-stringify-tinderbox", "stanford-crypto-aes",
- "stanford-crypto-ccm", "stanford-crypto-pbkdf2",
- "stanford-crypto-sha256-iterative"].each {
- | name |
- KRAKEN.add KrakenBenchmark.new(name)
- }
- ARGV.each {
- | vm |
- if vm =~ /([a-zA-Z0-9_ ]+):/
- name = $1
- nameKind = :given
- vm = $~.post_match
- else
- name = "Conf\##{$vms.length+1}"
- nameKind = :auto
- end
- $stderr.puts "#{name}: #{vm}" if $verbosity >= 1
- $vms << VM.new(Pathname.new(vm).realpath, name, nameKind, nil)
- }
-
- if $vms.empty?
- quickFail("Please specify at least on configuraiton on the command line.",
- "Insufficient arguments")
- end
-
- $vms.each {
- | vm |
- if vm.vmType != :jsc and $timeMode != :date
- $timeMode = :date
- $stderr.puts "Warning: using Date.now() instead of preciseTime() because #{vm} doesn't support the latter."
- end
- }
-
- if FileTest.exist? BENCH_DATA_PATH
- cmd = "rm -rf #{BENCH_DATA_PATH}"
- $stderr.puts ">> #{cmd}" if $verbosity >= 2
- raise unless system cmd
- end
-
- Dir.mkdir BENCH_DATA_PATH
-
- if $needToCopyVMs
- canCopyIntoBenchPath = true
- $vms.each {
- | vm |
- canCopyIntoBenchPath = false unless vm.canCopyIntoBenchPath
- }
-
- if canCopyIntoBenchPath
- $vms.each {
- | vm |
- $stderr.puts "Copying #{vm} into #{BENCH_DATA_PATH}..."
- vm.copyIntoBenchPath
- }
- $stderr.puts "All VMs are in place."
- else
- $stderr.puts "Warning: don't know how to copy some VMs into #{BENCH_DATA_PATH}, so I won't do it."
- end
- end
-
- if $measureGC and $measureGC != true
- found = false
- $vms.each {
- | vm |
- if vm.name == $measureGC
- found = true
- end
- }
- unless found
- $stderr.puts "Warning: --measure-gc option ignored because no VM is named #{$measureGC}"
- end
- end
-
- if $outer*$inner == 1
- $stderr.puts "Warning: will only collect one sample per benchmark/VM. Confidence interval calculation will fail."
- end
-
- $stderr.puts "Using timeMode = #{$timeMode}." if $verbosity >= 1
-
- $suites = []
-
- if $includeSunSpider and not SUNSPIDER.empty?
- $suites << SUNSPIDER
- end
-
- if $includeV8 and not V8.empty?
- $suites << V8
- end
-
- if $includeKraken and not KRAKEN.empty?
- $suites << KRAKEN
- end
-
- $benchmarks = []
- $suites.each {
- | suite |
- $benchmarks += suite.benchmarks
- }
-
- $runPlans = []
- $vms.each {
- | vm |
- $benchmarks.each {
- | benchmark |
- $outer.times {
- | iteration |
- $runPlans << BenchRunPlan.new(benchmark, vm, iteration)
- }
- }
- }
-
- $runPlans.shuffle!
-
- $suitepad = $suites.collect {
- | suite |
- suite.to_s.size
- }.max + 1
-
- $benchpad = ($benchmarks +
- ["<arithmetic> *", "<geometric> *", "<harmonic> *"]).collect {
- | benchmark |
- if benchmark.respond_to? :name
- benchmark.name.size
- else
- benchmark.size
- end
- }.max + 1
- $vmpad = $vms.collect {
- | vm |
- vm.to_s.size
- }.max + 1
-
- if $prepare
- File.open("#{BENCH_DATA_PATH}/runscript", "w") {
- | file |
- file.puts "echo \"HOSTNAME:\\c\""
- file.puts "hostname"
- file.puts "echo"
- file.puts "echo \"HARDWARE:\\c\""
- file.puts "/usr/sbin/sysctl hw.model"
- file.puts "echo"
- file.puts "set -e"
- $script = file
- $runPlans.each_with_index {
- | plan, idx |
- if $verbosity == 0 and not $silent
- text1 = lpad(idx.to_s,$runPlans.size.to_s.size)+"/"+$runPlans.size.to_s
- text2 = plan.benchmark.to_s+"/"+plan.vm.to_s
- file.puts("echo "+("\r#{text1} #{rpad(text2,$suitepad+1+$benchpad+1+$vmpad)}".inspect)[0..-2]+"\\c\" 1>&2")
- file.puts("echo "+("\r#{text1} #{text2}".inspect)[0..-2]+"\\c\" 1>&2")
- end
- plan.emitRunCode
- }
- if $verbosity == 0 and not $silent
- file.puts("echo "+("\r#{$runPlans.size}/#{$runPlans.size} #{' '*($suitepad+1+$benchpad+1+$vmpad)}".inspect)[0..-2]+"\\c\" 1>&2")
- file.puts("echo "+("\r#{$runPlans.size}/#{$runPlans.size}".inspect)+" 1>&2")
- end
- }
- end
-
- if $run
- unless $remoteHosts.empty?
- $stderr.puts "Packaging benchmarking directory for remote hosts..." if $verbosity==0
- Dir.chdir(TEMP_PATH) {
- cmd = "tar -czf payload.tar.gz benchdata"
- $stderr.puts ">> #{cmd}" if $verbosity>=2
- raise unless system(cmd)
- }
-
- def grokHost(host)
- if host =~ /:([0-9]+)$/
- "-p " + $1 + " " + $~.pre_match.inspect
- else
- host.inspect
- end
- end
-
- def sshRead(host, command)
- cmd = "ssh #{$sshOptions.collect{|x| x.inspect}.join(' ')} #{grokHost(host)} #{command.inspect}"
- $stderr.puts ">> #{cmd}" if $verbosity>=2
- result = ""
- IO.popen(cmd, "r") {
- | inp |
- inp.each_line {
- | line |
- $stderr.puts "#{host}: #{line}" if $verbosity>=2
- result += line
- }
- }
- raise "#{$?}" unless $?.success?
- result
- end
-
- def sshWrite(host, command, data)
- cmd = "ssh #{$sshOptions.collect{|x| x.inspect}.join(' ')} #{grokHost(host)} #{command.inspect}"
- $stderr.puts ">> #{cmd}" if $verbosity>=2
- IO.popen(cmd, "w") {
- | outp |
- outp.write(data)
- }
- raise "#{$?}" unless $?.success?
- end
-
- $remoteHosts.each {
- | host |
- $stderr.puts "Sending benchmark payload to #{host}..." if $verbosity==0
-
- remoteTempPath = JSON::parse(sshRead(host, "cat ~/.bencher"))["tempPath"]
- raise unless remoteTempPath
-
- sshWrite(host, "cd #{remoteTempPath.inspect} && rm -rf benchdata && tar -xz", IO::read("#{TEMP_PATH}/payload.tar.gz"))
-
- $stderr.puts "Running on #{host}..." if $verbosity==0
-
- parseAndDisplayResults(sshRead(host, "cd #{(remoteTempPath+'/benchdata').inspect} && sh runscript"))
- }
- end
-
- if not $remoteHosts.empty? and $alsoLocal
- $stderr.puts "Running locally..."
- end
-
- if $remoteHosts.empty? or $alsoLocal
- parseAndDisplayResults(runAndGetResults)
- end
- end
-
- $analyze.each_with_index {
- | filename, index |
- if index >= 1
- puts
- end
- parseAndDisplayResults(IO::read(filename))
- }
-
- if $prepare and not $run and $analyze.empty?
- puts wrap("Benchmarking script and data are in #{BENCH_DATA_PATH}. You can run "+
- "the benchmarks and get the results by doing:", 78)
- puts
- puts "cd #{BENCH_DATA_PATH}"
- puts "sh runscript > results.txt"
- puts
- puts wrap("Then you can analyze the results by running bencher with the same arguments "+
- "as now, but replacing --prepare-only with --analyze results.txt.", 78)
- end
- rescue => e
- fail(e)
- end
-
-
|