From b0a4f9f662c05f021608809fc50fbc633fbc9091 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Wed, 17 Mar 2021 11:06:49 -0400 Subject: [PATCH] test: ekf by_iter --- .../applications/ekf/by_iteration/.gitignore | 3 + .../applications/ekf/by_iteration/README.md | 9 +++ .../applications/ekf/by_iteration/debug.sh | 19 +++++++ .../ekf/by_iteration/initial_state.dat | Bin 0 -> 5088 bytes .../ekf/by_iteration/one_iteration.dat | Bin 0 -> 5088 bytes .../applications/ekf/by_iteration/run.sh | 53 ++++++++++++++++++ .../applications/ekf/by_iteration/spec.json | 42 ++++++++++++++ .../ekf/by_iteration/three_iterations.dat | Bin 0 -> 5088 bytes .../ekf/by_iteration/two_iterations.dat | Bin 0 -> 5088 bytes 9 files changed, 126 insertions(+) create mode 100644 runtime/experiments/applications/ekf/by_iteration/.gitignore create mode 100644 runtime/experiments/applications/ekf/by_iteration/README.md create mode 100755 runtime/experiments/applications/ekf/by_iteration/debug.sh create mode 100644 runtime/experiments/applications/ekf/by_iteration/initial_state.dat create mode 100644 runtime/experiments/applications/ekf/by_iteration/one_iteration.dat create mode 100755 runtime/experiments/applications/ekf/by_iteration/run.sh create mode 100644 runtime/experiments/applications/ekf/by_iteration/spec.json create mode 100644 runtime/experiments/applications/ekf/by_iteration/three_iterations.dat create mode 100644 runtime/experiments/applications/ekf/by_iteration/two_iterations.dat diff --git a/runtime/experiments/applications/ekf/by_iteration/.gitignore b/runtime/experiments/applications/ekf/by_iteration/.gitignore new file mode 100644 index 0000000..343f11e --- /dev/null +++ b/runtime/experiments/applications/ekf/by_iteration/.gitignore @@ -0,0 +1,3 @@ +*res.dat +rt.log +log.csv diff --git a/runtime/experiments/applications/ekf/by_iteration/README.md b/runtime/experiments/applications/ekf/by_iteration/README.md new file mode 100644 index 0000000..20079c5 --- /dev/null +++ b/runtime/experiments/applications/ekf/by_iteration/README.md @@ -0,0 +1,9 @@ +# EKF + +Executes TinyEKF as shows by [You Chong's GPS example](http://www.mathworks.com/matlabcentral/fileexchange/31487-extended-kalman-filter-ekf--for-gps) + +In order to be compatible with the stdin/stdout model of serverless, the input and output files are binary concatenations of various C structs. + +See `main()` in `runtime/tests/TinyEKF/extras/c/gps_ekf_fn.c` for specifics. + +This test executes multiple iterations, comparing the binary result against a known memoized result stored at `expected_result.dat`. diff --git a/runtime/experiments/applications/ekf/by_iteration/debug.sh b/runtime/experiments/applications/ekf/by_iteration/debug.sh new file mode 100755 index 0000000..6ab3666 --- /dev/null +++ b/runtime/experiments/applications/ekf/by_iteration/debug.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Executes the runtime in GDB +# Substitutes the absolute path from the container with a path relatively derived from the location of this script +# This allows debugging outside of the Docker container +# Also disables pagination and stopping on SIGUSR1 + +experiment_directory=$(pwd) +project_directory=$(cd ../../../.. && pwd) +binary_directory=$(cd "$project_directory"/bin && pwd) + +export LD_LIBRARY_PATH="$binary_directory:$LD_LIBRARY_PATH" +export PATH="$binary_directory:$PATH" + +gdb --eval-command="handle SIGUSR1 nostop" \ + --eval-command="handle SIGPIPE nostop" \ + --eval-command="set pagination off" \ + --eval-command="set substitute-path /sledge/runtime $project_directory" \ + --eval-command="run $experiment_directory/spec.json" \ + sledgert diff --git a/runtime/experiments/applications/ekf/by_iteration/initial_state.dat b/runtime/experiments/applications/ekf/by_iteration/initial_state.dat new file mode 100644 index 0000000000000000000000000000000000000000..9a960e1e986d6142e00a0c8c803f8c9463a7e541 GIT binary patch literal 5088 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 literal 0 HcmV?d00001 diff --git a/runtime/experiments/applications/ekf/by_iteration/one_iteration.dat b/runtime/experiments/applications/ekf/by_iteration/one_iteration.dat new file mode 100644 index 0000000000000000000000000000000000000000..1229f11ef4c95e3f33a405927779bff326f70651 GIT binary patch literal 5088 zcmeHLc{o*T7eBW$3$cXKz^sgE2_* zx1V<+Up595t0$R8R$X-=CX4&pnnk3FD6fk!?rwQx!Uh3N#0LpWg zFSpq>f?8^87JY|TNlAH2F*2p@5v?<*XTvi$Qdc?>wckBDOc}t5J4!QBs4~G&@9tL@ zh`1;nZ}ZFLlwL_$Q~laolmXXg=y`4`)sPvkJ-Z>9@Kw%PS=(AlMaFWgtUQXTRv%N- zntiE6Pm^6iWk@;Uuu%N!V09Eh9h}pf(o#-%z7RN1o*6~RDOS}uYGx3gk$;K;uWcY4 zj=fxJbSDGpFYagi6#uzjxX#a^{+^BNVEgxsAB+4d9<$&&*y8xl+F!+EK3oS|9RFD> zCK8-D^5>Ht($}$S?_}u;t49>B#5}cYyWek3wEs2U$J@r(CCaL5rt!%Ko+M=(@o0Z+ z8F>3?ljys6uhn&jkEYhq`7&Lsw8>i6>HHPiwrUN@&uG6tzqx3BW3*}wy`EmCl)5^w ziuOJCJP)e2Z>IhJcsxIz1NYOvF4m*J#d_hnasU1M=#Rrb))(u9=lyoy7}ek6{rH~k zpWoldxc>1U^)VjXAH{ty?^o+!JhtEC`O)~V*1>pef0XxodB0i*G(h34*sK?$-xB@# zJPD83V+6_MECBi=?2CaK z3uqsxQE`<0K%7Q;?m@b=p!v3=K5G!40m4x=T3Zzg9e|>Lp;L@23oy|>h>)HX(uI%a z+kyIIAwDI9dni<|JsHIWLtb+nr6uogzA=LzW$0N3eC;Zky^K8lSOXPLkP0T@=hir1!=1{WD{uukfyD+j;+~l1UwTUc9 z*%q3=K8)Njcd1Lk`x*kB$?R3uEX#qPdH8e{jKH2zFv$?WQP1@!u{;Vy61SN8Euv*F|hr%KM}uLrwq zM^=w0vX8Hnx0gApn|^+=!_H)n8+yBsZ-se~<&8C^sJ@sW)*b5hAAg1BYqH4qdwJ>- zT|fJw45hngKkWwHIC;CyO&}6KMZKu%S=s zr9QqBXN!Gb-4ddDV!}TWWTz%p()rAWJe}i*`DmTNo~u2`xa(*hy*{yQ#2YfEiuR$A zA-6oSkAHjXt81OYcp5*Lbx?6n-ab0t@n5fN0!8O&Uw5$FKr;d66BEvF4A<)G&IW_7 zkb^QtS%X^TGDSfM0kRZr)5q9Zz+uv`wKqZ!e0(u^ukS3$_WI|WUVD-pdk1gPl*=G5xDNEQeu+%1?#~5~w zE#!ne(Stz=mlFp(HHCIMEvK5L0W_&eE3Vya3AETIjTaxy15;BsNtf7K0=ZkCJ8$$Yc-I0KDrt0cDcw$@KniLC|w`aFc62Wu&1d*f37UNu)juwtp<>YTv8`HC&a% z6PACb;@=ExIO$bKjfv}7czUxo=$KwuaP;DMpm8ai`>skKE|{WLl>b>CV%@Ml9!Q5= zG;cGS3-^!v%t!q^MtbKWU1uQuB9Km44?H)X&j`(d_el@!$62KN4WuvD5$lC@xsK-7 zJfX{bKW90Z?pParKh6=vEpIuiWa3kf2cRAB6^t}h@kvARj$j_dxGZ*FK_@`3Slm~WRz~y}C6yv!EiT0O|9ecF{ zsVhaRt&c1IL6Jk;Lsfi&C>(zgJxuv#Wh@ccvvUpWbR^}WsK;nu>_Xst95(o)2Mq~h^uo0*NlMdKEm7;ZZ_hqN5iWxh2wfLx>#3;AB_ zi*h(NCaP>t(tT^L?vd-kc&ek-{@`@V2g h*(bR_SKAqc9GBdmt%_gz=Sl9*`1>9HZim0u{RQ<9%KHES literal 0 HcmV?d00001 diff --git a/runtime/experiments/applications/ekf/by_iteration/run.sh b/runtime/experiments/applications/ekf/by_iteration/run.sh new file mode 100755 index 0000000..870dca1 --- /dev/null +++ b/runtime/experiments/applications/ekf/by_iteration/run.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# Executes the runtime in GDB +# Substitutes the absolute path from the container with a path relatively derived from the location of this script +# This allows debugging outside of the Docker container +# Also disables pagination and stopping on SIGUSR1 + +experiment_directory=$(pwd) +runtime_directory=$(cd ../../../.. && pwd) +binary_directory=$(cd "$runtime_directory"/bin && pwd) +log="$experiment_directory/log.csv" + +# Copy data if not here +if [[ ! -f "./initial_state.dat" ]]; then + cp $runtime_directory/tests/TinyEKF/extras/c/ekf_raw.dat ./initial_state.dat +fi + +if [ "$1" != "-d" ]; then + SLEDGE_SANDBOX_PERF_LOG=$log PATH="$binary_directory:$PATH" LD_LIBRARY_PATH="$binary_directory:$LD_LIBRARY_PATH" sledgert "$experiment_directory/spec.json" >rt.log 2>&1 & + sleep 2 +else + echo "Running under gdb" +fi + +one_iteration_expected_result="$(tr -d '\0' <./one_iteration.dat)" +two_iterations_expected_result="$(tr -d '\0' <./two_iterations.dat)" +three_iterations_expected_result="$(tr -d '\0' <./three_iterations.dat)" + +success_count=0 +total_count=50 + +for ((i = 0; i < total_count; i++)); do + echo "$i" + curl -H 'Expect:' -H "Content-Type: application/octet-stream" --data-binary "@initial_state.dat" localhost:10000 2>/dev/null >./one_iteration_res.dat + curl -H 'Expect:' -H "Content-Type: application/octet-stream" --data-binary "@one_iteration_res.dat" localhost:10001 2>/dev/null >./two_iterations_res.dat + curl -H 'Expect:' -H "Content-Type: application/octet-stream" --data-binary "@two_iterations_res.dat" localhost:10002 2>/dev/null >./three_iterations_res.dat + if diff -s one_iteration_res.dat one_iteration.dat && diff -s two_iterations_res.dat two_iterations.dat && diff -s three_iterations_res.dat three_iterations.dat; then + success_count=$((success_count + 1)) + else + echo "FAIL" + exit + fi + + rm *_res.dat +done + +echo "$success_count / $total_count" + +if [ "$1" != "-d" ]; then + sleep 5 + echo -n "Running Cleanup: " + pkill sledgert >/dev/null 2>/dev/null + echo "[DONE]" +fi diff --git a/runtime/experiments/applications/ekf/by_iteration/spec.json b/runtime/experiments/applications/ekf/by_iteration/spec.json new file mode 100644 index 0000000..2043944 --- /dev/null +++ b/runtime/experiments/applications/ekf/by_iteration/spec.json @@ -0,0 +1,42 @@ +{ + "active": "yes", + "name": "ekf_first_iter", + "path": "ekf_wasm.so", + "port": 10000, + "relative-deadline-us": 50000, + "argsize": 1, + "http-req-headers": [], + "http-req-content-type": "application/octet-stream", + "http-req-size": 1024000, + "http-resp-headers": [], + "http-resp-size": 1024000, + "http-resp-content-type": "application/octet-stream" +}, +{ + "active": "yes", + "name": "ekf_second_iter", + "path": "ekf_wasm.so", + "port": 10001, + "relative-deadline-us": 50000, + "argsize": 1, + "http-req-headers": [], + "http-req-content-type": "application/octet-stream", + "http-req-size": 1024000, + "http-resp-headers": [], + "http-resp-size": 1024000, + "http-resp-content-type": "application/octet-stream" +}, +{ + "active": "yes", + "name": "ekf_third_iter", + "path": "ekf_wasm.so", + "port": 10002, + "relative-deadline-us": 50000, + "argsize": 1, + "http-req-headers": [], + "http-req-content-type": "application/octet-stream", + "http-req-size": 1024000, + "http-resp-headers": [], + "http-resp-size": 1024000, + "http-resp-content-type": "application/octet-stream" +} diff --git a/runtime/experiments/applications/ekf/by_iteration/three_iterations.dat b/runtime/experiments/applications/ekf/by_iteration/three_iterations.dat new file mode 100644 index 0000000000000000000000000000000000000000..cc0ab73b218ed0c9578c425ca5666eecc94f6f3f GIT binary patch literal 5088 zcmeHLc{EjP8$W1H;ZPZ`^r6X=Q^}D1?qeQ0PRdC%sL&B9k%V+Iq)f?eo^&+bBAN%4 z{Yr$~icloVlu#5&RK9b+-gjHet-I>$`|~?%@to&*e!pk!-q2Gj^|LuR094=Dp+xR z%vsaT+f_$E7e;~2?L>LVa(^~+q*D_mf#%FY{V;E2hG|GBc(z6xm z!a@7tIfba-al|_`?%ck8cNc@}jy@V(MfP+x$DStQ<&VvI%PJ-;v|kAK zR@^4+|CIb=lVl4Os3|kl(4(9(ayHUvuumo0vmWquR~;lAU=T~T;}I2JlU!bY_byd+ z=vH^d@ZAJqQN``>s3htgG(5?IGRo*eyYxK6Vq&d(ptzy97oqL9>xAG%DzR_=n*&)cqo=9o(fE`5;(DGXH_-mT{(7WE_IAZ5blza| zWj5chjP}LzhZ>eRG}8V+KHeYif#(@m7wa+5V!iO*c>aNN4CG-S>x*^5`+j?F%o=F% zd3?_f#1Hf_Z(#gKeay%9M|t1F{c0V|$M$=Del-58bub^>AMN`++^^Qb{C47!)Nc}8 zXE(4Zs?dsj#sy81Q5HSATzH3-Kz%*q%R^z42%Wb$fxD45W;skHG3buBYi$vCWr*lIIw0@GXr z)+@-_`4@CixZfPa)6Cpod$oN%xK%TzN~O*X=*gIhnP|AcQq7}P9Si^!wPt6%gxcWH zDKG7XJNk$`H0MgxFAMPo&&w?K+B**@Wrd92v>L#OfGMWgdFrq$?(sCgoid>JsVv7R zvW^Hw`w3LO&Z&#~DI;EPaB&H!+6Z)H#XB`pmV@j*J=JGk|2=S6%Ya zet6EUs2}Eu9obs6LT5gx_Eb8g8(<9{-9FW2vtI!)k)Gj57rY;y6ZgZsXvv3Oug@+6 z2a7_+8pi5_Bj_Bek)FGdE+5c-Y&2&n>W6t+ZV1>LO(e#Op5HQSw+x%L6o86M%Nt|pQL^E?szHV2iItRxwWq#p`--)?S!J&E(z*NC5;d3^D;H6JWAsQDJvr# zhj3`Wo@*-S?2=34IfUnhbf0?KcOIR6B(T_@#xsoNUZ>tOqVqbp#WKS`?xlT+wl|8e zwwy-zb|T(t-TMbSt$<9rH#tkj4$Q5&_Bn@T2@8wi-~nWL)wYYg=glPSs_usujG`Hf0%`a)wzM z=eUKy33g7qxMf5L0T<1E>^1wLA=DDe^!d10L3LLf{Y76ap!7rw8)McqFyg-D?<17W z09S2Dg8oZ2pnuyiElHaM@Nv+Z7Z)Ueq(|P8YDx}({U2L;g1d+-j9ORnITJMb)y_Am z*94_(PP|o|Ea<;i#LQX12@;~ zOWcv;1i&cmCqhj?<8Pt(kicPF(-&?)H|%4?#YYan9@Q~JcpVfsJss*GWUT<(XSj{p zoe)cOUR{vl>bH<8Tqi6FGYF-c8)8n3_w}G~TsnGkyj=S>qQ;rOBtR;Rx?1P7xuwjJ zz<3-l+OWRmbb1oOzpkA2?jxVBgYh^XlN@iFbYqL?x)6AVHmgDg1Ih@8>WM6)<8AO~ z(e<%5MLypUnhO?xkyP`{?%8=aBfDf3Dcjp~Jf+=_9DPuGqgtJRwhGT==9VO5(n6`r zEF^vnIaenhW-jy2K6}*GL{Z>IE)F@TyC=_|OlQq%86LTataYgVL;VJyETYolRx}5Y s)w|9%c8c!LKCO=9c8KoJk2%u={<=R~-hS<{9 literal 0 HcmV?d00001 diff --git a/runtime/experiments/applications/ekf/by_iteration/two_iterations.dat b/runtime/experiments/applications/ekf/by_iteration/two_iterations.dat new file mode 100644 index 0000000000000000000000000000000000000000..a98da81d6a116e98a9c47d947b202bfd7e6bf81b GIT binary patch literal 5088 zcmeHLdpMM78>f&C6l$H4Ln=mDIpvi18Ck8Inn|QWqeA0+)}~S6v=_dyRovyET zEa@f7ZhWU`dZ34}t|=~i%vOT~@(XQ3YWZXy;`2hdd_5Bz^G6;a%r|JT$({jDbPhX~ zN?1cL87+mQ=?0MPe~FNS8ZkzujogIK;OV;bxdgoVoqT2E_VXxr))h0xgxfeCspv0PAUm zbn!*|;W;rM#%;0+HN8K=1pS;)@p|@hV2jS78|irl>GB5cr-0^cMSK{i_U_s-Ev6E< znE&sW3K0C11TRhSAM?o{7-#%n;@=bgf1dYR{MEP27BLe)Aq%i?VbS`&Z$gQ`s`WS zW~WvW<08)+>KKp6ZmW_2Iese<8fdPuygQCKXUy%@o1aC*-y{oO2p1FfB?k*%_mmSe zUvbz)zxR^-J#9~)GMh=2y=Uz&r5_@S!|z}By?&PHvL9;RBGX9vrbzrKd9#{S(KHac zkb8nO8)<7Vu4^L-4tB?>x!odl0%pfnCo~ZoZyP7=-0MtQMq54VVdWD$GJb6}&Q2!N zD;yG;9~b#tJZ8atu*LCDwV#W}e7Fy`IR2@Y zN62dhdKIO0Q2%3or)XJ=RVRr%6(p%$@ev-N{6FIFc^|r#*j#KIr10EMzIuUCIpwcn zs3yFP=>8zyq9(ueG^dBEFaJ8CX{CA%RbO2@T+*BIgz~5J3u|VwzEyZgxK8m^G}~+Iu83-U#t_}_pj&1sOc7;$A|3n z`sqH#O^<)9kMY=kEbc>fpW6rHvHcLw$HqUm55{BrvAiFu``kVl&m&&NB+ooG<_h+# zyVfGc*$9eC9Rr1AETDyiXkAVa4MwiFIDflI6!I9l3mKz5>Iu>P$+vk&zwMvT_Tm2*M0$^RD(S8MJPFci9 zL%4H}=iDnM7$7W2D*bVeIk4V#MJS_P3M@i;Iw4(_qx}}5ISmnCIKst^24w^{ML8MC@+Rq)$xdHKE+|Rewt5|NzU|2F%T1s&Lc3HGI|9+_sTsrZy zeVgF^O~FWRtL*9_@=#=Xs-58e&G0~Ox#%)oAY-e-o+r3}^ADS-Wckv8_@=tkV|&Bt z4i56fvGGWHVlrF$+~Ej%f-!f0iBBZmJN1|CA_lDl`Xxt4X^$}j$FJb)aWv2KLIaFS zrt$^b%num4R#AC><`VyeqaDcS5jw-3hr4X@sC;9}S=J=;9EBgP?>?R;@)MQ66s+5! z_4X>|`zN36lu&w1)q6ztrY>c2sXV*dVS$F&RVts~aYhviU!d}D<>ltS%BV#?k2uE2 z4EUj-gvuv=A6)1E-4zNyBR*KUVQoI;-xhJ}uhpxj>iazGvdc~Ts640K>f{sl0OjX5 zST^P-a46rc=F!8Zz;X(2&k?uPvui>=k8pQS8<8o0NY!gdrO&#Tbdjppp!;7}d5}Wo z9R?-CY^Lfde=4=MB3`(k@(XNRt$Fq_6#i83wKwzIgQ@&3ksXo=;qT|0yx;nw>p4DO z9$`r9o9UXf4wNm6{!&=f4$ONO=>Qgd1-39>ybPw$XBVz0Q`Uvud3gcG4*)Dq zCxcDzehIpLT03gzsK9vjgvsJ}T2OnUbWh|`Yd9n2^kutubf{eUYI4RbCVcMfJ3332 z0qeXk)XAP9V9+;yr{h+wfmvdv^ZHnpaK|@=Ro^YPg#TPjBOL5Zz$xpi=5B0D0Gq5f zsIrWJ%x`NO&lgz&n!#m0`-l{nSQN#I>y!s(2O^&FeHMUBzG#v@p#TDR*WRenSOHWE z8O>3vzW`aww*)L&uMG3n%PK$XnhB?fk^GHAD}dNjy1Cnw5}4X%;};;O1ueC{%}s3< zf><|Oq|XAR!%eiW5ZWsk&3_urIf>@MdIuq0b&!7TNT(%84-VS<7TOQ*fzN3kI*&@E zdjisT6zRx9dM!e_WTE|wxZ3C85*9F778g=H!T>Ml?{-RUb^?)EyN;C-3}A}l7yXvB z#<;P7lWGNnKd>281HJ6uM+xv6)#G^h&{F>=(L2DzZz=uTeH}m)>T?Ix;$xj@x;FFe-J#E>TzA$U8Mf6Yj#Hk?kDwqm)|w=@F8(LXPhSH;hjK;a@N?Mn01gm z7_P_fWw;Qy9>=@9=C4%>IZ5<~d5Y&8@uvFVdK~BOs{7&Ep2LFw38*f8ybKBn>1caK z=?ZKn|4z+PfmOMY8V;akwCmJ7RZs53@!OZU&1|~N+llNfUJzX}b=6+g$01xLCo{uC zCrs&IDe~9t`#ylq(Ec9YVEJ$hGdGwiMDL)x?z{YDa!m-mNY7|wcI