hqlresource.cpp 170 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "jlib.hpp"
  15. #include "hqlexpr.hpp"
  16. #include "hqlattr.hpp"
  17. #include "hqlmeta.hpp"
  18. #include "hqlutil.hpp"
  19. #include "hqlcpputil.hpp"
  20. #include "hqlthql.hpp"
  21. #include "hqlcatom.hpp"
  22. #include "hqlfold.hpp"
  23. #include "hqlcerrors.hpp"
  24. #include "hqltrans.ipp"
  25. #include "hqlpmap.hpp"
  26. #include "hqltcppc.ipp"
  27. #include "hqlttcpp.ipp"
  28. #include "hqlresource.ipp"
  29. #include "../../thorlcr/thorutil/thbufdef.hpp"
  30. #define MINIMAL_CHANGES
  31. #define MAX_INLINE_COMMON_COUNT 5
  32. //#define TRACE_RESOURCING
  33. //#define VERIFY_RESOURCING
  34. //#define SPOT_UNCONDITIONAL_CONDITIONS
  35. #define DEFAULT_LARGEMEM_BUFFER_SIZE (0x58000000) // ~ 1.4GB
  36. #define DEFAULT_MAX_SOCKETS 2000 // configurable by setting max_sockets in .ini
  37. #define DEFAULT_TOTAL_MEMORY ((1024*1024*1800)-DEFAULT_LARGEMEM_BUFFER_SIZE)
  38. #define FIXED_CLUSTER_SIZE 400
  39. #define MEM_Const_Minimal (1*1024*1024)
  40. #define DEFAULT_MAX_ACTIVITIES 100
  41. //=== The following provides information about how each kind of activity is resourced ====
  42. static void setHashResources(IHqlExpression * expr, CResources & resources, const CResourceOptions & options)
  43. {
  44. unsigned memneeded = MEM_Const_Minimal+resources.clusterSize*4*DISTRIBUTE_SINGLE_BUFFER_SIZE+DISTRIBUTE_PULL_BUFFER_SIZE;
  45. resources.set(RESslavememory, memneeded).set(REShashdist, 1);
  46. }
  47. //MORE: Use a single function to map an hqlexpression to an activity kind.
  48. void getResources(IHqlExpression * expr, CResources & resources, const CResourceOptions & options)
  49. {
  50. //MORE: What effect should a child query have? Definitely the following, but what about other resourcing?
  51. if (options.isChildQuery || queryHint(expr, lightweightAtom))
  52. {
  53. resources.setLightweight();
  54. return;
  55. }
  56. bool isLocal = isLocalActivity(expr);
  57. bool isGrouped = isGroupedActivity(expr);
  58. switch (expr->getOperator())
  59. {
  60. case no_join:
  61. case no_selfjoin:
  62. case no_denormalize:
  63. case no_denormalizegroup:
  64. if (isKeyedJoin(expr) || expr->hasAttribute(_lightweight_Atom))
  65. resources.setLightweight();
  66. else if (expr->hasAttribute(lookupAtom))
  67. {
  68. if (expr->hasAttribute(fewAtom))
  69. {
  70. resources.setLightweight().set(RESslavememory, MEM_Const_Minimal+LOOKUPJOINL_SMART_BUFFER_SIZE);
  71. resources.setManyToMasterSockets(1);
  72. }
  73. else
  74. {
  75. resources.setHeavyweight().set(RESslavememory, MEM_Const_Minimal+LOOKUPJOINL_SMART_BUFFER_SIZE);
  76. resources.setManyToMasterSockets(1);
  77. }
  78. }
  79. else if (expr->hasAttribute(hashAtom))
  80. {
  81. resources.setHeavyweight();
  82. setHashResources(expr, resources, options);
  83. }
  84. else
  85. {
  86. resources.setHeavyweight().set(RESslavememory, MEM_Const_Minimal+SORT_BUFFER_TOTAL+JOINR_SMART_BUFFER_SIZE);
  87. if (!isLocal)
  88. {
  89. #ifndef SORT_USING_MP
  90. resources.setManyToManySockets(2);
  91. #endif
  92. }
  93. }
  94. break;
  95. case no_dedup:
  96. if (isGrouped || (!expr->hasAttribute(allAtom) && !expr->hasAttribute(hashAtom)))
  97. {
  98. resources.setLightweight();
  99. if (!isGrouped && !isLocal)
  100. {
  101. resources.set(RESslavememory, MEM_Const_Minimal+DEDUP_SMART_BUFFER_SIZE);
  102. resources.setManyToMasterSockets(1);
  103. }
  104. }
  105. else if (isLocal)
  106. {
  107. resources.setHeavyweight().set(RESslavememory, MEM_Const_Minimal+DEDUP_SMART_BUFFER_SIZE);
  108. //This can't be right....
  109. //resources.setManyToMasterSockets(1);
  110. }
  111. else
  112. {
  113. //hash dedup.
  114. resources.setHeavyweight();
  115. setHashResources(expr, resources, options);
  116. }
  117. break;
  118. case no_rollup:
  119. resources.setLightweight();
  120. if (!isGrouped && !isLocal)
  121. {
  122. resources.set(RESslavememory, MEM_Const_Minimal+DEDUP_SMART_BUFFER_SIZE);
  123. //MORE: Is this still correct?
  124. resources.setManyToMasterSockets(1);
  125. }
  126. break;
  127. case no_distribute:
  128. case no_keyeddistribute:
  129. resources.setLightweight();
  130. setHashResources(expr, resources, options);
  131. break;
  132. case no_subsort:
  133. if (expr->hasAttribute(manyAtom))
  134. resources.setHeavyweight();
  135. else
  136. resources.setLightweight();
  137. break;
  138. case no_sort:
  139. if (isGrouped)
  140. {
  141. if (expr->hasAttribute(manyAtom))
  142. resources.setHeavyweight();
  143. else
  144. resources.setLightweight();
  145. }
  146. else if (expr->hasAttribute(fewAtom) && isLocal)
  147. resources.setLightweight();
  148. else if (isLocal)
  149. resources.setHeavyweight();
  150. else
  151. {
  152. resources.setHeavyweight();
  153. #ifndef SORT_USING_MP
  154. resources.setManyToManySockets(2);
  155. #endif
  156. }
  157. break;
  158. case no_topn:
  159. resources.setLightweight();
  160. break;
  161. case no_pipe:
  162. //surely it should be something like this.
  163. resources.setLightweight().set(RESslavesocket, 1);
  164. break;
  165. case no_table:
  166. {
  167. IHqlExpression * mode = expr->queryChild(2);
  168. if (mode && mode->getOperator() == no_pipe)
  169. {
  170. resources.setLightweight().set(RESslavesocket, 1);
  171. }
  172. else
  173. {
  174. resources.setLightweight();
  175. if (expr->hasAttribute(_workflowPersist_Atom) && expr->hasAttribute(distributedAtom))
  176. setHashResources(expr, resources, options); // may require a hash distribute
  177. }
  178. break;
  179. }
  180. case no_output:
  181. {
  182. IHqlExpression * filename = expr->queryChild(1);
  183. if (expr->hasAttribute(_spill_Atom))
  184. {
  185. //resources.setLightweight(); // assume no resources(!)
  186. }
  187. else if (filename && filename->getOperator() == no_pipe)
  188. {
  189. resources.setLightweight().set(RESslavesocket, 1);
  190. }
  191. else if (filename && !filename->isAttribute())
  192. {
  193. resources.setLightweight();
  194. }
  195. else
  196. {
  197. resources.setLightweight().set(RESslavememory, WORKUNITWRITE_SMART_BUFFER_SIZE);
  198. }
  199. break;
  200. }
  201. case no_distribution:
  202. resources.setLightweight().set(RESmastersocket, 16).set(RESslavesocket, 1);
  203. break;
  204. case no_aggregate:
  205. case no_newaggregate:
  206. {
  207. IHqlExpression * grouping = queryRealChild(expr, 3);
  208. if (grouping)
  209. {
  210. //Is this really correct???
  211. resources.setLightweight();
  212. setHashResources(expr, resources, options);
  213. }
  214. else
  215. {
  216. resources.setLightweight();
  217. //if (!isGrouped)
  218. // resources.set(RESmastersocket, 16).set(RESslavesocket, 1);
  219. }
  220. }
  221. break;
  222. case no_hqlproject:
  223. resources.setLightweight();
  224. //Add a flag onto count project to indicate it is a different variety.
  225. if (expr->hasAttribute(_countProject_Atom) && !isLocal)
  226. resources.set(RESslavememory, COUNTPROJECT_SMART_BUFFER_SIZE);
  227. break;
  228. case no_enth:
  229. resources.setLightweight();
  230. if (!isLocal)
  231. resources.set(RESslavememory, CHOOSESETS_SMART_BUFFER_SIZE);
  232. break;
  233. case no_metaactivity:
  234. if (expr->hasAttribute(pullAtom))
  235. resources.setLightweight().set(RESslavememory, PULL_SMART_BUFFER_SIZE);
  236. break;
  237. case no_setresult:
  238. case no_extractresult:
  239. case no_outputscalar:
  240. resources.setLightweight();//.set(RESmastersocket, 1).set(RESslavesocket, 1);
  241. break;
  242. case no_choosesets:
  243. resources.setLightweight();
  244. if (!isLocal || expr->hasAttribute(enthAtom) || expr->hasAttribute(lastAtom))
  245. resources.set(RESslavememory, CHOOSESETS_SMART_BUFFER_SIZE);
  246. break;
  247. case no_iterate:
  248. resources.setLightweight();
  249. if (!isGrouped && !isLocal)
  250. resources.setManyToMasterSockets(1).set(RESslavememory, ITERATE_SMART_BUFFER_SIZE);
  251. break;
  252. case no_choosen:
  253. resources.setLightweight().set(RESslavememory, FIRSTN_SMART_BUFFER_SIZE);
  254. break;
  255. case no_spill:
  256. case no_spillgraphresult:
  257. //assumed to take no resources;
  258. break;
  259. case no_addfiles:
  260. case no_merge:
  261. {
  262. resources.setLightweight();
  263. unsigned bufSize = FUNNEL_PERINPUT_BUFF_SIZE*expr->numChildren();
  264. if (bufSize < FUNNEL_MIN_BUFF_SIZE) bufSize = FUNNEL_MIN_BUFF_SIZE;
  265. resources.set(RESslavememory, MEM_Const_Minimal+bufSize);
  266. break;
  267. }
  268. case no_compound:
  269. //MORE: Should really be the total resources for the lhs... Really needs more thought.
  270. break;
  271. case no_libraryselect:
  272. //Do not allocate any resources for this, we don't want it to cause a spill under any circumstances
  273. break;
  274. case no_split:
  275. //Should really be included in the cost....
  276. default:
  277. resources.setLightweight();
  278. break;
  279. }
  280. }
  281. CResources & CResources::setLightweight()
  282. {
  283. return set(RESslavememory, 0x10000).set(RESactivities, 1);
  284. }
  285. CResources & CResources::setHeavyweight()
  286. {
  287. return set(RESslavememory, 0x100000).set(RESheavy, 1).set(RESactivities, 1);
  288. }
  289. //-------------------------------------------------------------------------------------------
  290. const char * queryResourceName(ResourceType kind)
  291. {
  292. switch (kind)
  293. {
  294. case RESslavememory: return "Slave Memory";
  295. case RESslavesocket: return "Slave Sockets";
  296. case RESmastermemory: return "Master Memory";
  297. case RESmastersocket: return "Master Sockets";
  298. case REShashdist: return "Hash Distributes";
  299. case RESheavy: return "Heavyweight";
  300. case RESactivities: return "Activities";
  301. }
  302. return "Unknown";
  303. }
  304. inline ResourcerInfo * queryResourceInfo(IHqlExpression * expr) { return (ResourcerInfo *)expr->queryBody()->queryTransformExtra(); }
  305. inline bool isResourcedActivity(IHqlExpression * expr)
  306. {
  307. ResourcerInfo * extra = queryResourceInfo(expr);
  308. return (extra && (extra->isActivity || extra->containsActivity));
  309. }
  310. bool isWorthForcingHoist(IHqlExpression * expr)
  311. {
  312. loop
  313. {
  314. switch (expr->getOperator())
  315. {
  316. case no_selectnth:
  317. case no_filter:
  318. case no_newaggregate:
  319. if (isResourcedActivity(expr->queryChild(0)))
  320. return true;
  321. break;
  322. default:
  323. return false;
  324. }
  325. expr = expr->queryChild(0);
  326. }
  327. }
  328. void CResources::add(const CResources & other)
  329. {
  330. for (unsigned i = 0; i < RESmax; i++)
  331. resource[i] += other.resource[i];
  332. }
  333. bool CResources::addExceeds(const CResources & other, const CResources & limit) const
  334. {
  335. for (unsigned i = 0; i < RESmax; i++)
  336. {
  337. if (resource[i] + other.resource[i] > limit.resource[i])
  338. {
  339. //DBGLOG("Cannot merge because limit for %s exceeded (%d cf %d)", queryResourceName((ResourceType)i), resource[i] + other.resource[i], limit.resource[i]);
  340. return true;
  341. }
  342. }
  343. return false;
  344. }
  345. StringBuffer & CResources::getExceedsReason(StringBuffer & reasonText, const CResources & other, const CResources & limit) const
  346. {
  347. bool first = true;
  348. for (unsigned i = 0; i < RESmax; i++)
  349. {
  350. if (resource[i] + other.resource[i] > limit.resource[i])
  351. {
  352. if (!first) reasonText.append(", ");
  353. first = false;
  354. reasonText.appendf("%s (%d>%d)", queryResourceName((ResourceType)i), resource[i] + other.resource[i], limit.resource[i]);
  355. }
  356. }
  357. return reasonText;
  358. }
  359. bool CResources::exceeds(const CResources & limit) const
  360. {
  361. for (unsigned i = 0; i < RESmax; i++)
  362. {
  363. if (resource[i] > limit.resource[i])
  364. return true;
  365. }
  366. return false;
  367. }
  368. void CResources::maximize(const CResources & other)
  369. {
  370. for (unsigned i = 0; i < RESmax; i++)
  371. {
  372. if (resource[i] < other.resource[i])
  373. resource[i] = other.resource[i];
  374. }
  375. }
  376. CResources & CResources::setManyToMasterSockets(unsigned numSockets)
  377. {
  378. set(RESslavesocket, numSockets);
  379. set(RESmastersocket, numSockets * clusterSize);
  380. return *this;
  381. }
  382. CResources & CResources::setManyToManySockets(unsigned numSockets)
  383. {
  384. return set(RESslavesocket, numSockets * clusterSize);
  385. }
  386. void CResources::sub(const CResources & other)
  387. {
  388. for (unsigned i = 0; i < RESmax; i++)
  389. resource[i] -= other.resource[i];
  390. }
  391. //===========================================================================
  392. inline bool isAffectedByResourcing(IHqlExpression * expr)
  393. {
  394. switch (expr->getOperator())
  395. {
  396. case no_record:
  397. case no_constant:
  398. case no_attr:
  399. return false;
  400. }
  401. return true;
  402. }
  403. bool isSimpleAggregateResult(IHqlExpression * expr)
  404. {
  405. //MORE: no_extractresult is really what is meant
  406. if (expr->getOperator() != no_extractresult)
  407. return false;
  408. IHqlExpression * value = expr->queryChild(0);
  409. if (value->getOperator() != no_datasetfromrow)
  410. return false;
  411. //MORE: This currently doesn't hoist selects from nested records, but not sure there is a syntax to do that either.
  412. IHqlExpression * ds = value->queryChild(0);
  413. if (!isSelectFirstRow(ds))
  414. return false;
  415. ds = ds->queryChild(0);
  416. if (ds->getOperator() != no_newaggregate)
  417. return false;
  418. return true;
  419. }
  420. bool lightweightAndReducesDatasetSize(IHqlExpression * expr)
  421. {
  422. switch (expr->getOperator())
  423. {
  424. case no_hqlproject:
  425. case no_newusertable:
  426. return reducesRowSize(expr);
  427. case no_dedup:
  428. if (isGroupedActivity(expr) || (!expr->hasAttribute(allAtom) && !expr->hasAttribute(hashAtom)))
  429. return true;
  430. break;
  431. case no_aggregate:
  432. case no_newaggregate:
  433. {
  434. IHqlExpression * grouping = queryRealChild(expr, 3);
  435. if (grouping)
  436. return false;
  437. return true;
  438. }
  439. case no_rollupgroup:
  440. case no_rollup:
  441. case no_choosen:
  442. case no_choosesets:
  443. case no_enth:
  444. case no_sample:
  445. case no_filter:
  446. case no_limit:
  447. case no_filtergroup:
  448. return true;
  449. case no_group:
  450. //removing grouping will reduce size of the spill file.
  451. if (expr->queryType()->queryGroupInfo() == NULL)
  452. return true;
  453. break;
  454. }
  455. return false;
  456. }
  457. bool heavyweightAndReducesSizeOrSkew(IHqlExpression * expr)
  458. {
  459. switch (expr->getOperator())
  460. {
  461. case no_aggregate:
  462. case no_newaggregate:
  463. {
  464. //more; hash aggregate?
  465. break;
  466. }
  467. case no_distribute:
  468. return true;
  469. }
  470. return false;
  471. }
  472. //---------------------------------------------------------------------------
  473. IHqlExpression * CResourceOptions::createSpillName(bool isGraphResult)
  474. {
  475. if (isGraphResult)
  476. return getSizetConstant(nextResult++);
  477. StringBuffer s;
  478. s.append("~spill::");
  479. getUniqueId(s);
  480. return createConstant(s.str());
  481. }
  482. //---------------------------------------------------------------------------
  483. IHqlExpression * appendUniqueAttr(IHqlExpression * expr)
  484. {
  485. return replaceOwnedProperty(expr, createUniqueId());
  486. }
  487. bool queryAddUniqueToActivity(IHqlExpression * expr)
  488. {
  489. if (!isSourceActivity(expr))
  490. return false;
  491. switch (expr->getOperator())
  492. {
  493. case no_workunit_dataset:
  494. case no_getgraphresult:
  495. case no_getgraphloopresult:
  496. case no_xmlproject:
  497. case no_datasetfromrow:
  498. case no_datasetfromdictionary:
  499. case no_rows:
  500. case no_allnodes:
  501. case no_thisnode:
  502. case no_select: // it can get lost, and that then causes inconsistent trees.
  503. return false;
  504. }
  505. return true;
  506. }
  507. //---------------------------------------------------------------------------
  508. ResourceGraphLink::ResourceGraphLink(ResourceGraphInfo * _sourceGraph, IHqlExpression * _sourceNode, ResourceGraphInfo * _sinkGraph, IHqlExpression * _sinkNode, LinkKind _linkKind)
  509. {
  510. assertex(_sourceGraph);
  511. sourceGraph.set(_sourceGraph);
  512. sourceNode.set(_sourceNode);
  513. sinkGraph.set(_sinkGraph);
  514. sinkNode.set(_sinkNode);
  515. assertex(!sinkGraph || sinkNode);
  516. linkKind = _linkKind;
  517. trace("create");
  518. }
  519. ResourceGraphLink::~ResourceGraphLink()
  520. {
  521. trace("delete");
  522. }
  523. void ResourceGraphLink::changeSourceGraph(ResourceGraphInfo * newGraph)
  524. {
  525. sourceGraph->sinks.zap(*this);
  526. sourceGraph.set(newGraph);
  527. newGraph->sinks.append(*this);
  528. trace("change source");
  529. }
  530. void ResourceGraphLink::changeSinkGraph(ResourceGraphInfo * newGraph)
  531. {
  532. sinkGraph->sources.zap(*this);
  533. sinkGraph.set(newGraph);
  534. newGraph->sources.append(*this);
  535. trace("change sink");
  536. }
  537. bool ResourceGraphLink::isRedundantLink()
  538. {
  539. ResourcerInfo * info = queryResourceInfo(sourceNode);
  540. return info->expandRatherThanSpill(false);
  541. }
  542. void ResourceGraphLink::trace(const char * name)
  543. {
  544. #ifdef TRACE_RESOURCING
  545. PrintLog("%s: %lx source(%lx,%lx) sink(%lx,%lx) %s", name, this, sourceGraph.get(), sourceNode->queryBody(), sinkGraph.get(), sinkNode ? sinkNode->queryBody() : NULL,
  546. linkKind == ConditionalLink ? "conditional" : linkKind == SequenceLink ? "sequence" : "");
  547. #endif
  548. }
  549. ResourceGraphDependencyLink::ResourceGraphDependencyLink(ResourceGraphInfo * _sourceGraph, IHqlExpression * _sourceNode, ResourceGraphInfo * _sinkGraph, IHqlExpression * _sinkNode)
  550. : ResourceGraphLink(_sourceGraph, _sourceNode, _sinkGraph, _sinkNode, UnconditionalLink)
  551. {
  552. }
  553. void ResourceGraphDependencyLink::changeSourceGraph(ResourceGraphInfo * newGraph)
  554. {
  555. sourceGraph.set(newGraph);
  556. trace("change source");
  557. }
  558. void ResourceGraphDependencyLink::changeSinkGraph(ResourceGraphInfo * newGraph)
  559. {
  560. sinkGraph.set(newGraph);
  561. newGraph->dependsOn.append(*this);
  562. trace("change sink");
  563. }
  564. //---------------------------------------------------------------------------
  565. ResourceGraphInfo::ResourceGraphInfo(CResourceOptions * _options) : resources(_options->clusterSize)
  566. {
  567. options = _options;
  568. depth = 0;
  569. depthSequence = -1;
  570. beenResourced = false;
  571. isUnconditional = false;
  572. mergedConditionSource = false;
  573. hasConditionSource = false;
  574. hasSequentialSource = false;
  575. isDead = false;
  576. startedGeneratingResourced = false;
  577. inheritedExpandedDependencies = false;
  578. cachedDependent.other = NULL;
  579. }
  580. ResourceGraphInfo::~ResourceGraphInfo()
  581. {
  582. }
  583. bool ResourceGraphInfo::addCondition(IHqlExpression * condition)
  584. {
  585. if (conditions.find(*condition) == NotFound)
  586. {
  587. conditions.append(*LINK(condition));
  588. #ifdef SPOT_UNCONDITIONAL_CONDITIONS
  589. IAtom * name = condition->queryName();
  590. IAtom * invName = NULL;
  591. if (name == trueAtom)
  592. invName = falseAtom;
  593. else if (name == falseAtom)
  594. invName = trueAtom;
  595. if (invName)
  596. {
  597. IHqlExpression * parent = condition->queryChild(1);
  598. OwnedHqlExpr invTag = createAttribute(invName, LINK(condition->queryChild(0)), LINK(parent));
  599. if (conditions.find(*invTag) != NotFound)
  600. {
  601. if (!parent)
  602. return true;
  603. return addCondition(parent);
  604. }
  605. }
  606. #endif
  607. }
  608. return false;
  609. }
  610. bool ResourceGraphInfo::isSharedInput(IHqlExpression * expr)
  611. {
  612. IHqlExpression * body = expr->queryBody();
  613. if (unbalancedExternalSources.contains(*body))
  614. return false;
  615. if (queryResourceInfo(expr)->expandRatherThanSplit())
  616. return false;
  617. unsigned numUses = 0;
  618. ForEachItemIn(i, balancedExternalSources)
  619. {
  620. if (body == &balancedExternalSources.item(i))
  621. numUses++;
  622. }
  623. //NumUses could be zero if an input should be expanded, and that input is shared by another graph which also expands
  624. //the input. E.g. project(meta(diskread).
  625. return numUses > 1;
  626. }
  627. void ResourceGraphInfo::addSharedInput(IHqlExpression * expr, IHqlExpression * mapped)
  628. {
  629. sharedInputs.append(*LINK(expr));
  630. sharedInputs.append(*LINK(mapped));
  631. }
  632. IHqlExpression * ResourceGraphInfo::queryMappedSharedInput(IHqlExpression * expr)
  633. {
  634. unsigned max = sharedInputs.ordinality();
  635. for (unsigned i=0; i < max; i+= 2)
  636. {
  637. if (expr == &sharedInputs.item(i))
  638. return &sharedInputs.item(i+1);
  639. }
  640. return NULL;
  641. }
  642. bool ResourceGraphInfo::allocateResources(const CResources & value, const CResources & limit)
  643. {
  644. if (resources.addExceeds(value, limit))
  645. return false;
  646. resources.add(value);
  647. return true;
  648. }
  649. bool ResourceGraphInfo::containsActiveSinks()
  650. {
  651. ForEachItemIn(idx, sinks)
  652. {
  653. ResourcerInfo * info = queryResourceInfo(sinks.item(idx).sourceNode);
  654. if (!info->expandRatherThanSpill(false))
  655. return true;
  656. }
  657. return false;
  658. }
  659. void ResourceGraphInfo::display()
  660. {
  661. StringBuffer s;
  662. s.appendf("graph %p src(", this);
  663. ForEachItemIn(idxs, sources)
  664. s.appendf("%p ", sources.item(idxs).sourceGraph.get());
  665. s.append(") dep(");
  666. ForEachItemIn(idxd, dependsOn)
  667. s.appendf("%p ", dependsOn.item(idxd).sourceGraph.get());
  668. s.append(")");
  669. if (isUnconditional)
  670. s.append(" <unconditional>");
  671. DBGLOG("%s", s.str());
  672. }
  673. void ResourceGraphInfo::getMergeFailReason(StringBuffer & reasonText, ResourceGraphInfo * otherGraph, const CResources & limit)
  674. {
  675. resources.getExceedsReason(reasonText, otherGraph->resources, limit);
  676. }
  677. unsigned ResourceGraphInfo::getDepth()
  678. {
  679. //If no graphs have been merged since this was last called it is still valid.
  680. if (depthSequence == options->state.updateSequence)
  681. return depth;
  682. depthSequence = options->state.updateSequence;
  683. depth = 0;
  684. ForEachItemIn(idx, dependsOn)
  685. {
  686. ResourceGraphInfo * source = dependsOn.item(idx).sourceGraph;
  687. if (source->getDepth() >= depth)
  688. depth = source->getDepth() + 1;
  689. }
  690. ForEachItemIn(idx2, sources)
  691. {
  692. ResourceGraphInfo * source = sources.item(idx2).sourceGraph;
  693. if (source->getDepth() >= depth)
  694. depth = source->getDepth() + 1;
  695. }
  696. return depth;
  697. }
  698. bool ResourceGraphInfo::hasSameConditions(ResourceGraphInfo & other)
  699. {
  700. if (conditions.ordinality() != other.conditions.ordinality())
  701. return false;
  702. ForEachItemIn(i, conditions)
  703. if (other.conditions.find(conditions.item(i)) == NotFound)
  704. return false;
  705. return true;
  706. }
  707. bool ResourceGraphInfo::evalDependentOn(ResourceGraphInfo & other, bool ignoreSources)
  708. {
  709. ForEachItemIn(idx, dependsOn)
  710. {
  711. ResourceGraphInfo * cur = dependsOn.item(idx).sourceGraph;
  712. if (cur == &other)
  713. return true;
  714. if (cur->isDependentOn(other, false))
  715. return true;
  716. }
  717. ForEachItemIn(idx2, sources)
  718. {
  719. ResourceGraphInfo * cur = sources.item(idx2).sourceGraph;
  720. if ((cur == &other) && !ignoreSources)
  721. return true;
  722. if (cur->isDependentOn(other, false))
  723. return true;
  724. }
  725. return false;
  726. }
  727. bool ResourceGraphInfo::isDependentOn(ResourceGraphInfo & other, bool ignoreSources)
  728. {
  729. //Cache the last query so that traversal doesn't convert a graph into a tree walk
  730. if ((cachedDependent.other == &other) && (cachedDependent.ignoreSources == ignoreSources) &&
  731. (cachedDependent.updateSequence == options->state.updateSequence))
  732. return cachedDependent.value;
  733. if (getDepth() <= other.getDepth())
  734. return false;
  735. cachedDependent.other = &other;
  736. cachedDependent.ignoreSources = ignoreSources;
  737. cachedDependent.updateSequence = options->state.updateSequence;
  738. cachedDependent.value = evalDependentOn(other, ignoreSources);
  739. return cachedDependent.value;
  740. }
  741. bool ResourceGraphInfo::isVeryCheap()
  742. {
  743. if (sinks.ordinality() != 1)
  744. return false;
  745. IHqlExpression * sourceNode = sinks.item(0).sourceNode;
  746. if (isSimpleAggregateResult(sourceNode))
  747. return true;
  748. // Not sure about the following....
  749. // if (sourceNode->getOperator() == no_setresult)
  750. // return true;
  751. //Could be other examples...
  752. return false;
  753. }
  754. bool ResourceGraphInfo::mergeInSource(ResourceGraphInfo & other, const CResources & limit, bool isConditionalLink)
  755. {
  756. bool mergeConditions = false;
  757. if (!isUnconditional)
  758. {
  759. //if it is conditional and it is very cheap then it is still more efficient to merge
  760. //rather than read from a spill file.
  761. if (other.isUnconditional || !hasSameConditions(other))
  762. {
  763. if ((hasConditionSource || !isVeryCheap()) && (other.sinks.ordinality() != 1))
  764. return false;
  765. mergeConditions = true;
  766. }
  767. }
  768. if (isDependentOn(other, true))
  769. return false;
  770. if (!options->canSplit())
  771. {
  772. //Don't merge two graphs that will cause a splitter to be created
  773. //Either already used internally, or an output will be merged twice
  774. HqlExprArray mergeNodes;
  775. ForEachItemIn(idx, sources)
  776. {
  777. ResourceGraphLink & cur = sources.item(idx);
  778. if (cur.sourceGraph == &other)
  779. {
  780. IHqlExpression * sourceNode = cur.sourceNode->queryBody();
  781. ResourcerInfo * info = queryResourceInfo(sourceNode);
  782. if ((info->numInternalUses() != 0) || (mergeNodes.find(*sourceNode) != NotFound) || info->preventMerge())
  783. return false;
  784. mergeNodes.append(*LINK(sourceNode));
  785. }
  786. }
  787. }
  788. if (options->checkResources() && !allocateResources(other.resources, limit))
  789. return false;
  790. if (hasSequentialSource && other.hasSequentialSource)
  791. return false;
  792. mergeGraph(other, isConditionalLink, mergeConditions);
  793. return true;
  794. }
  795. void ResourceGraphInfo::mergeGraph(ResourceGraphInfo & other, bool isConditionalLink, bool mergeConditions)
  796. {
  797. #ifdef TRACE_RESOURCING
  798. DBGLOG("Merging%s source into%s sink", other.isUnconditional ? "" : " conditional", isUnconditional ? "" : " conditional");
  799. other.display();
  800. display();
  801. PrintLog("Merge %p into %p", &other, this);
  802. #endif
  803. if (other.hasConditionSource)
  804. hasConditionSource = true;
  805. if (other.hasSequentialSource)
  806. {
  807. assertex(!hasSequentialSource);
  808. hasSequentialSource = true;
  809. }
  810. //Recalculate the dependents, because sources of the source merged in may no longer be indirect
  811. //although they may be via another path.
  812. options->noteGraphsChanged();
  813. //If was very cheap and merged into an unconditional graph, make sure this is now tagged as
  814. //unconditional...
  815. if (other.isUnconditional)
  816. isUnconditional = true;
  817. //We need to stop spills being an arm of a conditional branch - otherwise they won't get executed.
  818. //so see if we have merged any conditional branches in
  819. if (isConditionalLink || other.mergedConditionSource)
  820. mergedConditionSource = true;
  821. if (mergeConditions)
  822. {
  823. //Replace conditions with those of parent. Only called when a very simple graph is
  824. //merged in, so replace conditions instead of merging
  825. conditions.kill();
  826. ForEachItemIn(i, other.conditions)
  827. conditions.append(OLINK(other.conditions.item(i)));
  828. }
  829. //sources and sinks are updated elsewhere...
  830. }
  831. bool ResourceGraphInfo::mergeInSibling(ResourceGraphInfo & other, const CResources & limit)
  832. {
  833. if ((!isUnconditional || !other.isUnconditional) && !hasSameConditions(other))
  834. return false;
  835. if (hasSequentialSource && other.hasSequentialSource)
  836. return false;
  837. if (isDependentOn(other, false) || other.isDependentOn(*this, false))
  838. return false;
  839. if (options->checkResources() && !allocateResources(other.resources, limit))
  840. return false;
  841. mergeGraph(other, false, false);
  842. return true;
  843. }
  844. void ResourceGraphInfo::removeResources(const CResources & value)
  845. {
  846. resources.sub(value);
  847. }
  848. //---------------------------------------------------------------------------
  849. static void appendCloneProperty(HqlExprArray & args, IHqlExpression * expr, IAtom * name)
  850. {
  851. IHqlExpression * prop = expr->queryAttribute(name);
  852. if (prop)
  853. args.append(*LINK(prop));
  854. }
  855. ResourcerInfo::ResourcerInfo(IHqlExpression * _original, CResourceOptions * _options)
  856. {
  857. original.set(_original);
  858. numUses = 0;
  859. numExternalUses = 0;
  860. gatheredDependencies = false;
  861. containsActivity = false;
  862. isActivity = false;
  863. transformed = NULL;
  864. conditionSourceCount = 0;
  865. pathToExpr = PathUnknown;
  866. outputToUseForSpill = NULL;
  867. isAlreadyInScope = false;
  868. isSpillPoint = false;
  869. options = _options;
  870. balanced = true;
  871. currentSource = 0;
  872. linkedFromChild = false;
  873. neverSplit = false;
  874. isConditionalFilter = false;
  875. }
  876. void ResourcerInfo::setConditionSource(IHqlExpression * condition, bool isFirst)
  877. {
  878. if (isFirst)
  879. {
  880. conditionSourceCount++;
  881. graph->hasConditionSource = true;
  882. }
  883. }
  884. bool ResourcerInfo::addCondition(IHqlExpression * condition)
  885. {
  886. conditions.append(*LINK(condition));
  887. return graph->addCondition(condition);
  888. }
  889. void ResourcerInfo::addSpillFlags(HqlExprArray & args, bool isRead)
  890. {
  891. IHqlExpression * grouping = (IHqlExpression *)original->queryType()->queryGroupInfo();
  892. if (grouping)
  893. args.append(*createAttribute(groupedAtom));
  894. if (outputToUseForSpill)
  895. {
  896. assertex(isRead);
  897. appendCloneProperty(args, outputToUseForSpill, __compressed__Atom);
  898. appendCloneProperty(args, outputToUseForSpill, jobTempAtom);
  899. appendCloneProperty(args, outputToUseForSpill, _spill_Atom);
  900. }
  901. else
  902. {
  903. args.append(*createAttribute(__compressed__Atom));
  904. args.append(*createAttribute(_spill_Atom));
  905. args.append(*createAttribute(_noReplicate_Atom));
  906. if (options->targetRoxie())
  907. args.append(*createAttribute(_noAccess_Atom));
  908. }
  909. if (isRead)
  910. {
  911. args.append(*createAttribute(_noVirtual_Atom)); // Don't interpret virtual fields as virtual...
  912. if (!original->isDataset() || hasSingleRow(original))
  913. args.append(*createAttribute(rowAtom)); // add a flag so the selectnth[1] can be removed later...
  914. }
  915. else
  916. {
  917. unsigned numUses = numExternalUses;
  918. if (false) // options->cloneConditionals)
  919. {
  920. //Remove all the links from conditional graphs...
  921. ForEachItemIn(i1, graph->sinks)
  922. {
  923. ResourceGraphLink & cur = graph->sinks.item(i1);
  924. if ((cur.sourceNode == original) && (cur.linkKind == ConditionalLink || !cur.sinkGraph->isUnconditional))
  925. numUses--;
  926. }
  927. numUses += calcNumConditionalUses();
  928. }
  929. args.append(*createAttribute(_tempCount_Atom, getSizetConstant(numUses)));
  930. }
  931. }
  932. bool ResourcerInfo::alwaysExpand()
  933. {
  934. return (original->getOperator() == no_mapto);
  935. }
  936. static IHqlExpression * stripTrueFalse(IHqlExpression * expr)
  937. {
  938. if (expr->queryName() == instanceAtom)
  939. {
  940. IHqlExpression * parent = expr->queryChild(2);
  941. if (parent)
  942. parent = stripTrueFalse(parent);
  943. return createAttribute(instanceAtom, LINK(expr->queryChild(0)), LINK(expr->queryChild(1)), parent);
  944. }
  945. else
  946. {
  947. IHqlExpression * parent = expr->queryChild(1);
  948. if (parent && parent->isAttribute())
  949. parent = stripTrueFalse(parent);
  950. return createAttribute(tempAtom, LINK(expr->queryChild(0)), parent);
  951. }
  952. }
  953. unsigned ResourcerInfo::calcNumConditionalUses()
  954. {
  955. //for thor and hthor, where the conditional graph is cloned, the maximum number of times it can be read
  956. //is 1 for a shared conditional graph, or once for each combination of conditions it is used as the
  957. //input for. However if it is used more than once in a single branch of a condition it needs to be counted
  958. //several times.
  959. //It is always better to overestimate than underestimate. (But even better to get it right.)
  960. HqlExprArray uniqueConditions;
  961. UnsignedArray uniqueCounts;
  962. ForEachItemIn(idx, conditions)
  963. {
  964. IHqlExpression & cur = conditions.item(idx);
  965. OwnedHqlExpr unique = stripTrueFalse(&cur);
  966. unsigned numOccurences = 0;
  967. ForEachItemIn(j, conditions)
  968. if (&conditions.item(j) == &cur)
  969. numOccurences++;
  970. unsigned match = uniqueConditions.find(*unique);
  971. if (match == NotFound)
  972. {
  973. uniqueConditions.append(*unique.getClear());
  974. uniqueCounts.append(numOccurences);
  975. }
  976. else
  977. {
  978. if (uniqueCounts.item(match) < numOccurences)
  979. uniqueCounts.replace(numOccurences, match);
  980. }
  981. }
  982. unsigned condUses = 0;
  983. ForEachItemIn(k, uniqueCounts)
  984. condUses += uniqueCounts.item(k);
  985. return condUses;
  986. }
  987. // Each aggregate has form. Setresult(select(selectnth(aggregate...,1),field),name,seq)
  988. IHqlExpression * ResourcerInfo::createAggregation(IHqlExpression * expr)
  989. {
  990. LinkedHqlExpr transformed = expr;
  991. ForEachItemIn(idx, aggregates)
  992. {
  993. IHqlExpression & cur = aggregates.item(idx);
  994. IHqlExpression * row2ds = cur.queryChild(0);
  995. IHqlExpression * selectnth = row2ds->queryChild(0);
  996. IHqlExpression * aggregate = selectnth->queryChild(0);
  997. IHqlExpression * aggregateRecord = aggregate->queryChild(1);
  998. assertex(aggregate->getOperator() == no_newaggregate);
  999. HqlExprArray aggargs, setargs;
  1000. //Through aggregate has form (dataset, record, transform, list of set results);
  1001. aggargs.append(*LINK(transformed));
  1002. aggargs.append(*LINK(aggregateRecord));
  1003. IHqlExpression * mapped = replaceSelector(aggregate->queryChild(2), original, expr->queryNormalizedSelector());
  1004. aggargs.append(*mapped);
  1005. OwnedHqlExpr active = createDataset(no_anon, LINK(aggregateRecord), NULL);
  1006. OwnedHqlExpr mappedSelect = replaceSelector(cur.queryChild(1), row2ds, active);
  1007. setargs.append(*LINK(active));
  1008. setargs.append(*LINK(mappedSelect));
  1009. unwindChildren(setargs, &cur, 1);
  1010. aggargs.append(*createValue(no_extractresult, makeVoidType(), setargs));
  1011. transformed.setown(createDataset(no_throughaggregate, aggargs));
  1012. }
  1013. return transformed.getClear();
  1014. }
  1015. bool ResourcerInfo::useGraphResult()
  1016. {
  1017. if (!options->useGraphResults)
  1018. return false;
  1019. if (linkedFromChild)
  1020. return true;
  1021. //Roxie converts spills into splitters, so best to retain them
  1022. if (options->targetClusterType == RoxieCluster)
  1023. return false;
  1024. return true;
  1025. }
  1026. bool ResourcerInfo::useGlobalResult()
  1027. {
  1028. return (linkedFromChild && !useGraphResult());
  1029. }
  1030. IHqlExpression * ResourcerInfo::createSpillName()
  1031. {
  1032. if (outputToUseForSpill)
  1033. return LINK(outputToUseForSpill->queryChild(1));
  1034. if (!spillName)
  1035. {
  1036. if (useGraphResult())
  1037. spillName.setown(options->createSpillName(true));
  1038. else if (useGlobalResult())
  1039. {
  1040. StringBuffer valueText;
  1041. getUniqueId(valueText.append("spill"));
  1042. spillName.setown(createConstant(valueText.str()));
  1043. }
  1044. else
  1045. spillName.setown(options->createSpillName(false));
  1046. }
  1047. return LINK(spillName);
  1048. }
  1049. IHqlExpression * ResourcerInfo::createSpilledRead(IHqlExpression * spillReason)
  1050. {
  1051. OwnedHqlExpr dataset;
  1052. HqlExprArray args;
  1053. IHqlExpression * record = original->queryRecord();
  1054. bool loseDistribution = true;
  1055. if (useGraphResult())
  1056. {
  1057. args.append(*LINK(record));
  1058. args.append(*LINK(options->graphIdExpr));
  1059. args.append(*createSpillName());
  1060. if (isGrouped(original))
  1061. args.append(*createAttribute(groupedAtom));
  1062. if (!original->isDataset())
  1063. args.append(*createAttribute(rowAtom));
  1064. args.append(*createAttribute(_spill_Atom));
  1065. IHqlExpression * recordCountAttr = queryRecordCountInfo(original);
  1066. if (recordCountAttr)
  1067. args.append(*LINK(recordCountAttr));
  1068. if (options->targetThor() && original->isDataset() && !options->isChildQuery)
  1069. args.append(*createAttribute(_distributed_Atom));
  1070. if (original->isDictionary())
  1071. dataset.setown(createDictionary(no_getgraphresult, args));
  1072. else
  1073. dataset.setown(createDataset(no_getgraphresult, args));
  1074. loseDistribution = false;
  1075. }
  1076. else if (useGlobalResult())
  1077. {
  1078. args.append(*LINK(record));
  1079. args.append(*createAttribute(nameAtom, createSpillName()));
  1080. args.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  1081. addSpillFlags(args, true);
  1082. IHqlExpression * recordCountAttr = queryRecordCountInfo(original);
  1083. if (recordCountAttr)
  1084. args.append(*LINK(recordCountAttr));
  1085. if (original->isDictionary())
  1086. dataset.setown(createDictionary(no_workunit_dataset, args));
  1087. else
  1088. dataset.setown(createDataset(no_workunit_dataset, args));
  1089. }
  1090. else
  1091. {
  1092. if (spilledDataset)
  1093. {
  1094. args.append(*LINK(spilledDataset));
  1095. args.append(*createSpillName());
  1096. }
  1097. else
  1098. {
  1099. args.append(*createSpillName());
  1100. args.append(*LINK(record));
  1101. }
  1102. args.append(*createValue(no_thor));
  1103. addSpillFlags(args, true);
  1104. args.append(*createUniqueId());
  1105. if (options->isChildQuery && options->targetRoxie())
  1106. {
  1107. args.append(*createAttribute(_colocal_Atom));
  1108. args.append(*createLocalAttribute());
  1109. }
  1110. if (spillReason)
  1111. args.append(*LINK(spillReason));
  1112. if (spilledDataset)
  1113. dataset.setown(createDataset(no_readspill, args));
  1114. else
  1115. {
  1116. IHqlExpression * recordCountAttr = queryRecordCountInfo(original);
  1117. if (recordCountAttr)
  1118. args.append(*LINK(recordCountAttr));
  1119. dataset.setown(createDataset(no_table, args));
  1120. }
  1121. loseDistribution = false;
  1122. }
  1123. dataset.setown(preserveTableInfo(dataset, original, loseDistribution, NULL));
  1124. return wrapRowOwn(dataset.getClear());
  1125. }
  1126. IHqlExpression * ResourcerInfo::createSpilledWrite(IHqlExpression * transformed)
  1127. {
  1128. assertex(!outputToUseForSpill);
  1129. HqlExprArray args;
  1130. if (useGraphResult())
  1131. {
  1132. assertex(options->graphIdExpr);
  1133. args.append(*LINK(transformed));
  1134. args.append(*LINK(options->graphIdExpr));
  1135. args.append(*createSpillName());
  1136. args.append(*createAttribute(_spill_Atom));
  1137. return createValue(no_setgraphresult, makeVoidType(), args);
  1138. }
  1139. else if (useGlobalResult())
  1140. {
  1141. args.append(*LINK(transformed));
  1142. args.append(*createAttribute(sequenceAtom, getLocalSequenceNumber()));
  1143. args.append(*createAttribute(namedAtom, createSpillName()));
  1144. addSpillFlags(args, false);
  1145. return createValue(no_output, makeVoidType(), args);
  1146. }
  1147. else
  1148. {
  1149. if (options->createSpillAsDataset)
  1150. {
  1151. IHqlExpression * value = LINK(transformed);
  1152. if (value->isDatarow())
  1153. value = createDatasetFromRow(value);
  1154. spilledDataset.setown(createDataset(no_commonspill, value));
  1155. args.append(*LINK(spilledDataset));
  1156. }
  1157. else
  1158. args.append(*LINK(transformed));
  1159. args.append(*createSpillName());
  1160. addSpillFlags(args, false);
  1161. if (options->createSpillAsDataset)
  1162. return createValue(no_writespill, makeVoidType(), args);
  1163. return createValue(no_output, makeVoidType(), args);
  1164. }
  1165. }
  1166. bool ResourcerInfo::okToSpillThrough()
  1167. {
  1168. bool isGraphResult = useGraphResult();
  1169. if (isGraphResult)
  1170. return options->allowThroughResult;
  1171. if (useGlobalResult())
  1172. return false;
  1173. return (options->allowThroughSpill && !options->createSpillAsDataset);
  1174. }
  1175. bool ResourcerInfo::spillSharesSplitter()
  1176. {
  1177. if (outputToUseForSpill || useGraphResult() || useGlobalResult())
  1178. return false;
  1179. if (okToSpillThrough())
  1180. return false;
  1181. if (!isSplit() || !balanced)
  1182. return false;
  1183. return true;
  1184. }
  1185. IHqlExpression * ResourcerInfo::createSpiller(IHqlExpression * transformed, bool reuseSplitter)
  1186. {
  1187. if (outputToUseForSpill)
  1188. return LINK(transformed);
  1189. if (!okToSpillThrough())
  1190. {
  1191. OwnedHqlExpr split;
  1192. if (reuseSplitter)
  1193. {
  1194. assertex(transformed->getOperator() == no_split);
  1195. split.set(transformed);
  1196. }
  1197. else
  1198. {
  1199. if (transformed->isDataset())
  1200. split.setown(createDataset(no_split, LINK(transformed), createComma(createAttribute(balancedAtom), createUniqueId())));
  1201. else
  1202. split.setown(createRow(no_split, LINK(transformed), createComma(createAttribute(balancedAtom), createUniqueId())));
  1203. split.setown(cloneInheritedAnnotations(original, split));
  1204. }
  1205. splitterOutput.setown(createSpilledWrite(split));
  1206. return split.getClear();
  1207. }
  1208. HqlExprArray args;
  1209. node_operator op;
  1210. args.append(*LINK(transformed));
  1211. if (useGraphResult())
  1212. {
  1213. op = no_spillgraphresult;
  1214. args.append(*LINK(options->graphIdExpr));
  1215. args.append(*createSpillName());
  1216. args.append(*createAttribute(_spill_Atom));
  1217. }
  1218. else
  1219. {
  1220. op = no_spill;
  1221. args.append(*createSpillName());
  1222. addSpillFlags(args, false);
  1223. }
  1224. OwnedHqlExpr spill;
  1225. if (original->isDatarow())
  1226. spill.setown(createRow(op, args));
  1227. else
  1228. spill.setown(createDataset(op, args));
  1229. return cloneInheritedAnnotations(original, spill);
  1230. }
  1231. IHqlExpression * ResourcerInfo::createSplitter(IHqlExpression * transformed)
  1232. {
  1233. if (transformed->getOperator() == no_libraryscopeinstance)
  1234. return LINK(transformed);
  1235. IHqlExpression * attr = createUniqueId();
  1236. if (balanced)
  1237. attr = createComma(attr, createAttribute(balancedAtom));
  1238. OwnedHqlExpr split;
  1239. if (transformed->isDataset())
  1240. split.setown(createDataset(no_split, LINK(transformed), attr));
  1241. else
  1242. split.setown(createRow(no_split, LINK(transformed), attr));
  1243. return cloneInheritedAnnotations(original, split);
  1244. }
  1245. IHqlExpression * ResourcerInfo::createTransformedExpr(IHqlExpression * expr)
  1246. {
  1247. LinkedHqlExpr transformed = expr;
  1248. if (aggregates.ordinality())
  1249. transformed.setown(createAggregation(transformed));
  1250. if (spillSharesSplitter())
  1251. {
  1252. transformed.setown(createSplitter(transformed));
  1253. if (isExternalSpill())
  1254. transformed.setown(createSpiller(transformed, true));
  1255. }
  1256. else
  1257. {
  1258. if (isExternalSpill())
  1259. transformed.setown(createSpiller(transformed, false));
  1260. if (isSplit())
  1261. transformed.setown(createSplitter(transformed));
  1262. else if (isSpilledWrite())
  1263. transformed.setown(createSpilledWrite(transformed));
  1264. }
  1265. return transformed.getClear();
  1266. }
  1267. bool ResourcerInfo::expandRatherThanSpill(bool noteOtherSpills)
  1268. {
  1269. if (options->shareDontExpand)
  1270. return expandRatherThanSplit();
  1271. IHqlExpression * expr = original;
  1272. if (!options->minimiseSpills || linkedFromChild)
  1273. noteOtherSpills = false;
  1274. if (noteOtherSpills)
  1275. {
  1276. ResourcerInfo * info = queryResourceInfo(expr);
  1277. if (info && info->isSpilledWrite())
  1278. return (info->transformed == NULL);
  1279. }
  1280. bool isFiltered = false;
  1281. bool isProcessed = false;
  1282. loop
  1283. {
  1284. ResourcerInfo * info = queryResourceInfo(expr);
  1285. if (info && info->neverSplit)
  1286. return true;
  1287. node_operator op = expr->getOperator();
  1288. switch (op)
  1289. {
  1290. case no_table:
  1291. {
  1292. //This is only executed for hthor/thor. Roxie has used expandRatherThanSplit().
  1293. //We need to balance the saving from reading reduced data in the other branches with the cost of
  1294. //writing the spill file to disk.
  1295. if (isFiltered && (numExternalUses >= options->filteredSpillThreshold))
  1296. return false;
  1297. IHqlExpression * mode = expr->queryChild(2);
  1298. switch (mode->getOperator())
  1299. {
  1300. case no_thor: case no_flat:
  1301. //MORE: The following is possibly better - but roxie should be able to read from non spill data files in child queries fine
  1302. //if ((options->targetClusterType == RoxieCluster) && linkedFromChild)) return false;
  1303. return true;
  1304. default:
  1305. return false;
  1306. }
  1307. }
  1308. case no_stepped:
  1309. return true;
  1310. case no_inlinetable:
  1311. {
  1312. IHqlExpression * transforms = expr->queryChild(0);
  1313. //The inline table code means this should generate smaller code, and more efficient
  1314. if (!isFiltered && !isProcessed && transforms->isConstant())
  1315. return true;
  1316. if (transforms->numChildren() > MAX_INLINE_COMMON_COUNT)
  1317. return false;
  1318. return true;
  1319. }
  1320. case no_getresult:
  1321. case no_temptable:
  1322. case no_rows:
  1323. case no_xmlproject:
  1324. case no_workunit_dataset:
  1325. return !isProcessed && !isFiltered;
  1326. case no_getgraphresult:
  1327. return !expr->hasAttribute(_streaming_Atom); // we must not duplicate streaming inputs!
  1328. case no_keyindex:
  1329. case no_newkeyindex:
  1330. if (!isFiltered)
  1331. return true;
  1332. return options->cloneFilteredIndex;
  1333. case no_datasetfromrow:
  1334. if (getNumActivityArguments(expr) == 0)
  1335. return true;
  1336. return false;
  1337. case no_fail:
  1338. case no_null:
  1339. return !expr->isAction();
  1340. case no_assertsorted:
  1341. case no_sorted:
  1342. case no_grouped:
  1343. case no_distributed:
  1344. case no_preservemeta:
  1345. case no_nofold:
  1346. case no_nohoist:
  1347. case no_section:
  1348. case no_sectioninput:
  1349. case no_dataset_alias:
  1350. expr = expr->queryChild(0);
  1351. break;
  1352. case no_newusertable:
  1353. case no_limit:
  1354. case no_keyedlimit:
  1355. expr = expr->queryChild(0);
  1356. isProcessed = true;
  1357. break;
  1358. case no_hqlproject:
  1359. if (expr->hasAttribute(_countProject_Atom) || expr->hasAttribute(prefetchAtom))
  1360. return false;
  1361. expr = expr->queryChild(0);
  1362. isProcessed = true;
  1363. break;
  1364. //MORE: Not so sure about all the following, include them so behaviour doesn't change
  1365. case no_compound_diskread:
  1366. case no_compound_disknormalize:
  1367. case no_compound_diskaggregate:
  1368. case no_compound_diskcount:
  1369. case no_compound_diskgroupaggregate:
  1370. case no_compound_indexread:
  1371. case no_compound_indexnormalize:
  1372. case no_compound_indexaggregate:
  1373. case no_compound_indexcount:
  1374. case no_compound_indexgroupaggregate:
  1375. case no_compound_childread:
  1376. case no_compound_childnormalize:
  1377. case no_compound_childaggregate:
  1378. case no_compound_childcount:
  1379. case no_compound_childgroupaggregate:
  1380. case no_compound_selectnew:
  1381. case no_compound_inline:
  1382. case no_datasetfromdictionary:
  1383. expr = expr->queryChild(0);
  1384. break;
  1385. case no_filter:
  1386. isFiltered = true;
  1387. expr = expr->queryChild(0);
  1388. break;
  1389. case no_select:
  1390. {
  1391. if (options->targetClusterType == RoxieCluster)
  1392. return false;
  1393. if (!isNewSelector(expr))
  1394. return true;
  1395. expr = expr->queryChild(0);
  1396. break;
  1397. }
  1398. default:
  1399. return false;
  1400. }
  1401. //The following reduces the number of spills by taking into account other spills.
  1402. if (noteOtherSpills)
  1403. {
  1404. ResourcerInfo * info = queryResourceInfo(expr);
  1405. if (info)
  1406. {
  1407. if (info->isSpilledWrite())
  1408. return (info->transformed == NULL);
  1409. if (info->numExternalUses)
  1410. {
  1411. if (isFiltered && (numExternalUses >= options->filteredSpillThreshold))
  1412. return false;
  1413. return true;
  1414. }
  1415. }
  1416. }
  1417. }
  1418. }
  1419. bool ResourcerInfo::expandRatherThanSplit()
  1420. {
  1421. //MORE: This doesn't really work - should do indexMatching first.
  1422. //should only expand if one side that uses this is also filtered
  1423. IHqlExpression * expr = original;
  1424. loop
  1425. {
  1426. ResourcerInfo * info = queryResourceInfo(expr);
  1427. if (info && info->neverSplit)
  1428. return true;
  1429. switch (expr->getOperator())
  1430. {
  1431. case no_keyindex:
  1432. case no_newkeyindex:
  1433. case no_rowset:
  1434. case no_getgraphloopresultset:
  1435. return true;
  1436. case no_null:
  1437. return !expr->isAction();
  1438. case no_inlinetable:
  1439. if (options->expandSingleConstRow && hasSingleRow(expr))
  1440. {
  1441. IHqlExpression * values = expr->queryChild(0);
  1442. if (values->queryChild(0)->isConstant())
  1443. return true;
  1444. }
  1445. return false;
  1446. case no_stepped:
  1447. case no_rowsetrange:
  1448. case no_rowsetindex:
  1449. return true;
  1450. case no_sorted:
  1451. case no_grouped:
  1452. case no_distributed:
  1453. case no_preservemeta:
  1454. case no_compound_diskread:
  1455. case no_compound_disknormalize:
  1456. case no_compound_diskaggregate:
  1457. case no_compound_diskcount:
  1458. case no_compound_diskgroupaggregate:
  1459. case no_compound_indexread:
  1460. case no_compound_indexnormalize:
  1461. case no_compound_indexaggregate:
  1462. case no_compound_indexcount:
  1463. case no_compound_indexgroupaggregate:
  1464. case no_compound_childread:
  1465. case no_compound_childnormalize:
  1466. case no_compound_childaggregate:
  1467. case no_compound_childcount:
  1468. case no_compound_childgroupaggregate:
  1469. case no_compound_selectnew:
  1470. case no_compound_inline:
  1471. case no_section:
  1472. case no_sectioninput:
  1473. case no_dataset_alias:
  1474. break;
  1475. case no_select:
  1476. if (options->targetClusterType == RoxieCluster)
  1477. return false;
  1478. if (!isNewSelector(expr))
  1479. {
  1480. if (!hasLinkCountedModifier(expr))
  1481. return false;
  1482. return true;
  1483. }
  1484. break;
  1485. case no_rows:
  1486. //If executing in a child query then you'll have less thread contention if the iterator is duplicated
  1487. //So should probably uncomment the following.
  1488. //return true;
  1489. return false;
  1490. default:
  1491. return false;
  1492. }
  1493. expr = expr->queryChild(0);
  1494. }
  1495. }
  1496. bool neverCommonUp(IHqlExpression * expr)
  1497. {
  1498. loop
  1499. {
  1500. node_operator op = expr->getOperator();
  1501. switch (op)
  1502. {
  1503. case no_keyindex:
  1504. case no_newkeyindex:
  1505. return true;
  1506. case no_filter:
  1507. expr = expr->queryChild(0);
  1508. break;
  1509. default:
  1510. return false;
  1511. }
  1512. }
  1513. }
  1514. bool ResourcerInfo::neverCommonUp()
  1515. {
  1516. return ::neverCommonUp(original);
  1517. }
  1518. bool ResourcerInfo::isExternalSpill()
  1519. {
  1520. if (expandRatherThanSpill(true) || (numInternalUses() == 0))
  1521. return false;
  1522. return (numExternalUses != 0);
  1523. }
  1524. bool ResourcerInfo::isSplit()
  1525. {
  1526. return numSplitPaths() > 1;
  1527. }
  1528. unsigned ResourcerInfo::numSplitPaths()
  1529. {
  1530. unsigned internal = numInternalUses();
  1531. if ((internal == 0) || !options->allowSplitBetweenSubGraphs)
  1532. return internal;
  1533. //MORE
  1534. return internal;
  1535. }
  1536. bool ResourcerInfo::isSpilledWrite()
  1537. {
  1538. if (numInternalUses() == 0)
  1539. return true;
  1540. return false;
  1541. }
  1542. IHqlExpression * ResourcerInfo::wrapRowOwn(IHqlExpression * expr)
  1543. {
  1544. if (!original->isDataset() && !original->isDictionary())
  1545. expr = createRow(no_selectnth, expr, getSizetConstant(1));
  1546. return expr;
  1547. }
  1548. //---------------------------------------------------------------------------
  1549. EclResourcer::EclResourcer(IErrorReceiver * _errors, IConstWorkUnit * _wu, ClusterType _targetClusterType, unsigned _clusterSize, const HqlCppOptions & _translatorOptions)
  1550. {
  1551. wu.set(_wu);
  1552. errors = _errors;
  1553. lockTransformMutex();
  1554. targetClusterType = _targetClusterType;
  1555. clusterSize = _clusterSize ? _clusterSize : FIXED_CLUSTER_SIZE;
  1556. insideNeverSplit = false;
  1557. insideSteppedNeverSplit = false;
  1558. sequential = false;
  1559. options.minimizeSpillSize = _translatorOptions.minimizeSpillSize;
  1560. unsigned totalMemory = _translatorOptions.resourceMaxMemory ? _translatorOptions.resourceMaxMemory : DEFAULT_TOTAL_MEMORY;
  1561. unsigned maxSockets = _translatorOptions.resourceMaxSockets ? _translatorOptions.resourceMaxSockets : DEFAULT_MAX_SOCKETS;
  1562. unsigned maxActivities = _translatorOptions.resourceMaxActivities ? _translatorOptions.resourceMaxActivities : DEFAULT_MAX_ACTIVITIES;
  1563. unsigned maxHeavy = _translatorOptions.resourceMaxHeavy;
  1564. unsigned maxDistribute = _translatorOptions.resourceMaxDistribute;
  1565. resourceLimit = new CResources(0);
  1566. resourceLimit->set(RESactivities, maxActivities);
  1567. switch (targetClusterType)
  1568. {
  1569. case ThorLCRCluster:
  1570. resourceLimit->set(RESheavy, maxHeavy).set(REShashdist, maxDistribute);
  1571. resourceLimit->set(RESmastersocket, maxSockets).set(RESslavememory,totalMemory);
  1572. resourceLimit->set(RESslavesocket, maxSockets).set(RESmastermemory, totalMemory);
  1573. break;
  1574. default:
  1575. resourceLimit->set(RESheavy, 0xffffffff).set(REShashdist, 0xffffffff);
  1576. resourceLimit->set(RESmastersocket, 0xffffffff).set(RESslavememory, 0xffffffff);
  1577. resourceLimit->set(RESslavesocket, 0xffffffff).set(RESmastermemory, 0xffffffff);
  1578. clusterSize = 1;
  1579. break;
  1580. }
  1581. if (_translatorOptions.unlimitedResources)
  1582. {
  1583. resourceLimit->set(RESheavy, 0xffffffff).set(REShashdist, 0xffffffff);
  1584. resourceLimit->set(RESmastersocket, 0xffffffff).set(RESslavememory,0xffffffff);
  1585. resourceLimit->set(RESslavesocket, 0xffffffff).set(RESmastermemory,0xffffffff);
  1586. }
  1587. options.isChildQuery = false;
  1588. options.targetClusterType = targetClusterType;
  1589. options.filteredSpillThreshold = _translatorOptions.filteredReadSpillThreshold;
  1590. options.allowThroughSpill = _translatorOptions.allowThroughSpill;
  1591. options.allowThroughResult = (targetClusterType != RoxieCluster) && (targetClusterType != ThorLCRCluster);
  1592. options.cloneFilteredIndex = (targetClusterType != RoxieCluster);
  1593. options.spillSharedConditionals = (targetClusterType == RoxieCluster);
  1594. options.shareDontExpand = (targetClusterType == RoxieCluster);
  1595. options.graphIdExpr = NULL;
  1596. //MORE The following doesn't always work - it gets sometimes confused about spill files - see latestheaderbuild for an example.
  1597. //Try again once cloneConditionals is false for thor
  1598. options.minimiseSpills = _translatorOptions.minimiseSpills;
  1599. spillMultiCondition = _translatorOptions.spillMultiCondition;
  1600. spotThroughAggregate = _translatorOptions.spotThroughAggregate && (targetClusterType != RoxieCluster) && (targetClusterType != ThorLCRCluster);
  1601. options.noConditionalLinks = (targetClusterType == RoxieCluster);
  1602. options.hoistResourced = _translatorOptions.hoistResourced;
  1603. options.useGraphResults = false; // modified by later call
  1604. options.groupedChildIterators = _translatorOptions.groupedChildIterators;
  1605. options.allowSplitBetweenSubGraphs = false;//(targetClusterType == RoxieCluster);
  1606. options.clusterSize = clusterSize;
  1607. options.preventKeyedSplit = _translatorOptions.preventKeyedSplit;
  1608. options.preventSteppedSplit = _translatorOptions.preventSteppedSplit;
  1609. options.minimizeSkewBeforeSpill = _translatorOptions.minimizeSkewBeforeSpill;
  1610. options.expandSingleConstRow = true;
  1611. options.createSpillAsDataset = _translatorOptions.optimizeSpillProject && (targetClusterType != HThorCluster);
  1612. options.combineSiblings = _translatorOptions.combineSiblingGraphs && (targetClusterType != HThorCluster) && (targetClusterType != RoxieCluster);
  1613. options.optimizeSharedInputs = _translatorOptions.optimizeSharedGraphInputs && options.combineSiblings;
  1614. }
  1615. EclResourcer::~EclResourcer()
  1616. {
  1617. delete resourceLimit;
  1618. unlockTransformMutex();
  1619. }
  1620. void EclResourcer::setChildQuery(bool value)
  1621. {
  1622. options.isChildQuery = value;
  1623. if (value)
  1624. options.createSpillAsDataset = false;
  1625. }
  1626. void EclResourcer::setNewChildQuery(IHqlExpression * graphIdExpr, unsigned numResults)
  1627. {
  1628. options.graphIdExpr = graphIdExpr;
  1629. options.nextResult = numResults;
  1630. }
  1631. void EclResourcer::changeGraph(IHqlExpression * expr, ResourceGraphInfo * newGraph)
  1632. {
  1633. ResourcerInfo * info = queryResourceInfo(expr);
  1634. info->graph.set(newGraph);
  1635. ForEachItemInRev(idx, links)
  1636. {
  1637. ResourceGraphLink & cur = links.item(idx);
  1638. if (cur.sourceNode == expr)
  1639. cur.changeSourceGraph(newGraph);
  1640. else if (cur.sinkNode == expr)
  1641. cur.changeSinkGraph(newGraph);
  1642. assertex(cur.sinkGraph != cur.sourceGraph);
  1643. }
  1644. }
  1645. ResourceGraphInfo * EclResourcer::createGraph()
  1646. {
  1647. ResourceGraphInfo * graph = new ResourceGraphInfo(&options);
  1648. graphs.append(*LINK(graph));
  1649. //PrintLog("Create graph %p", graph);
  1650. return graph;
  1651. }
  1652. void EclResourcer::connectGraphs(ResourceGraphInfo * sourceGraph, IHqlExpression * sourceNode, ResourceGraphInfo * sinkGraph, IHqlExpression * sinkNode, LinkKind kind)
  1653. {
  1654. ResourceGraphLink * link = new ResourceGraphLink(sourceGraph, sourceNode, sinkGraph, sinkNode, kind);
  1655. links.append(*link);
  1656. if (sourceGraph)
  1657. sourceGraph->sinks.append(*link);
  1658. if (sinkGraph)
  1659. sinkGraph->sources.append(*link);
  1660. }
  1661. ResourcerInfo * EclResourcer::queryCreateResourceInfo(IHqlExpression * expr)
  1662. {
  1663. IHqlExpression * body = expr->queryBody();
  1664. ResourcerInfo * info = (ResourcerInfo *)body->queryTransformExtra();
  1665. if (!info)
  1666. {
  1667. info = new ResourcerInfo(expr, &options);
  1668. body->setTransformExtraOwned(info);
  1669. }
  1670. return info;
  1671. }
  1672. void EclResourcer::replaceGraphReferences(IHqlExpression * expr, ResourceGraphInfo * oldGraph, ResourceGraphInfo * newGraph)
  1673. {
  1674. ResourcerInfo * info = queryResourceInfo(expr);
  1675. if (!info || !info->containsActivity)
  1676. return;
  1677. if (info->isActivity && info->graph != oldGraph)
  1678. return;
  1679. info->graph.set(newGraph);
  1680. unsigned first = getFirstActivityArgument(expr);
  1681. unsigned last = first + getNumActivityArguments(expr);
  1682. for (unsigned idx=first; idx < last; idx++)
  1683. replaceGraphReferences(expr->queryChild(idx), oldGraph, newGraph);
  1684. }
  1685. void EclResourcer::removeLink(ResourceGraphLink & link, bool keepExternalUses)
  1686. {
  1687. ResourcerInfo * info = (ResourcerInfo *)queryResourceInfo(link.sourceNode);
  1688. assertex(info && info->numExternalUses > 0);
  1689. if (!keepExternalUses)
  1690. info->numExternalUses--;
  1691. if (link.sinkGraph)
  1692. link.sinkGraph->sources.zap(link);
  1693. link.sourceGraph->sinks.zap(link);
  1694. links.zap(link);
  1695. }
  1696. void EclResourcer::replaceGraphReferences(ResourceGraphInfo * oldGraph, ResourceGraphInfo * newGraph)
  1697. {
  1698. ForEachItemIn(idx1, oldGraph->sinks)
  1699. {
  1700. ResourceGraphLink & sink = oldGraph->sinks.item(idx1);
  1701. replaceGraphReferences(sink.sourceNode, oldGraph, newGraph);
  1702. }
  1703. ForEachItemInRev(idx2, links)
  1704. {
  1705. ResourceGraphLink & cur = links.item(idx2);
  1706. if (cur.sourceGraph == oldGraph)
  1707. {
  1708. if (cur.sinkGraph == newGraph)
  1709. removeLink(cur, false);
  1710. else
  1711. cur.changeSourceGraph(newGraph);
  1712. }
  1713. else if (cur.sinkGraph == oldGraph)
  1714. {
  1715. if (cur.sourceGraph == newGraph)
  1716. removeLink(cur, false);
  1717. else
  1718. cur.changeSinkGraph(newGraph);
  1719. }
  1720. }
  1721. }
  1722. //------------------------------------------------------------------------------------------
  1723. // PASS1: Gather information about splitter locations..
  1724. void EclResourcer::tagActiveCursors(HqlExprCopyArray & activeRows)
  1725. {
  1726. ForEachItemIn(i, activeRows)
  1727. {
  1728. IHqlExpression & cur = activeRows.item(i);
  1729. activeSelectors.append(cur);
  1730. queryCreateResourceInfo(&cur)->isAlreadyInScope = true;
  1731. }
  1732. }
  1733. inline bool projectSelectorDatasetToField(IHqlExpression * row)
  1734. {
  1735. return ((row->getOperator() == no_selectnth) && getFieldCount(row->queryRecord()) > 1);
  1736. }
  1737. static HqlTransformerInfo eclHoistLocatorInfo("EclHoistLocator");
  1738. class EclHoistLocator : public NewHqlTransformer
  1739. {
  1740. public:
  1741. EclHoistLocator(HqlExprCopyArray & _originalMatches, HqlExprArray & _matches, BoolArray & _singleNode, BoolArray & _alwaysHoistMatches)
  1742. : NewHqlTransformer(eclHoistLocatorInfo), originalMatched(_originalMatches), matched(_matches), singleNode(_singleNode), alwaysHoistMatches(_alwaysHoistMatches)
  1743. {
  1744. alwaysSingle = true;
  1745. }
  1746. void analyseChild(IHqlExpression * expr, bool _alwaysSingle)
  1747. {
  1748. alwaysSingle = _alwaysSingle;
  1749. analyse(expr, 0);
  1750. }
  1751. void noteDataset(IHqlExpression * expr, IHqlExpression * hoisted, bool alwaysHoist)
  1752. {
  1753. unsigned match = originalMatched.find(*expr);
  1754. if (match == NotFound)
  1755. {
  1756. if (!hoisted)
  1757. hoisted = expr;
  1758. originalMatched.append(*expr);
  1759. matched.append(*LINK(hoisted));
  1760. alwaysHoistMatches.append(alwaysHoist);
  1761. singleNode.append(alwaysSingle);
  1762. }
  1763. else
  1764. {
  1765. if (alwaysHoist && !alwaysHoistMatches.item(match))
  1766. alwaysHoistMatches.replace(true, match);
  1767. if (alwaysSingle && !singleNode.item(match))
  1768. singleNode.replace(true, match);
  1769. }
  1770. }
  1771. void noteScalar(IHqlExpression * expr, IHqlExpression * value)
  1772. {
  1773. if (!originalMatched.contains(*expr))
  1774. {
  1775. OwnedHqlExpr hoisted;
  1776. if (value->getOperator() == no_select)
  1777. {
  1778. bool isNew;
  1779. IHqlExpression * row = querySelectorDataset(value, isNew);
  1780. if(isNew || row->isDatarow())
  1781. {
  1782. if (projectSelectorDatasetToField(row))
  1783. {
  1784. IHqlExpression * ds = row->queryChild(0);
  1785. //Project down to a single field.so implicit fields can still be optimized
  1786. IHqlExpression * field = value->queryChild(1);
  1787. OwnedHqlExpr record = createRecord(field);
  1788. OwnedHqlExpr self = getSelf(record);
  1789. OwnedHqlExpr activeDs = createRow(no_activetable, LINK(ds->queryNormalizedSelector()));
  1790. OwnedHqlExpr selected = replaceSelector(value, row, activeDs);
  1791. OwnedHqlExpr assign = createAssign(createSelectExpr(LINK(self), LINK(field)), selected.getClear());
  1792. OwnedHqlExpr transform = createValue(no_newtransform, makeTransformType(record->getType()), LINK(assign));
  1793. OwnedHqlExpr projectedDs = createDataset(no_newusertable, LINK(ds), createComma(LINK(record), LINK(transform)));
  1794. hoisted.setown(replaceChild(row, 0, projectedDs));
  1795. }
  1796. if (!hoisted)
  1797. hoisted.set(row);
  1798. }
  1799. }
  1800. else if (value->getOperator() == no_createset)
  1801. {
  1802. IHqlExpression * ds = value->queryChild(0);
  1803. IHqlExpression * selected = value->queryChild(1);
  1804. OwnedHqlExpr field;
  1805. //Project down to a single field.so implicit fields can still be optimized
  1806. if (selected->getOperator() == no_select)
  1807. field.set(selected->queryChild(1));
  1808. else
  1809. field.setown(createField(valueId, selected->getType(), NULL));
  1810. OwnedHqlExpr record = createRecord(field);
  1811. OwnedHqlExpr self = getSelf(record);
  1812. OwnedHqlExpr assign = createAssign(createSelectExpr(LINK(self), LINK(field)), LINK(selected));
  1813. OwnedHqlExpr transform = createValue(no_newtransform, makeTransformType(record->getType()), LINK(assign));
  1814. hoisted.setown(createDataset(no_newusertable, LINK(ds), createComma(LINK(record), LINK(transform))));
  1815. }
  1816. if (!hoisted)
  1817. {
  1818. OwnedHqlExpr field = createField(valueId, value->getType(), NULL);
  1819. OwnedHqlExpr record = createRecord(field);
  1820. OwnedHqlExpr self = getSelf(record);
  1821. OwnedHqlExpr assign = createAssign(createSelectExpr(LINK(self), LINK(field)), LINK(value));
  1822. OwnedHqlExpr transform = createValue(no_transform, makeTransformType(record->getType()), LINK(assign));
  1823. hoisted.setown(createRow(no_createrow, LINK(transform)));
  1824. }
  1825. originalMatched.append(*expr);
  1826. matched.append(*hoisted.getClear());
  1827. alwaysHoistMatches.append(true);
  1828. singleNode.append(true);
  1829. }
  1830. }
  1831. protected:
  1832. HqlExprCopyArray & originalMatched;
  1833. HqlExprArray & matched;
  1834. BoolArray & singleNode;
  1835. BoolArray & alwaysHoistMatches;
  1836. bool alwaysSingle;
  1837. };
  1838. class EclChildSplitPointLocator : public EclHoistLocator
  1839. {
  1840. public:
  1841. EclChildSplitPointLocator(IHqlExpression * _original, HqlExprCopyArray & _selectors, HqlExprCopyArray & _originalMatches, HqlExprArray & _matches, BoolArray & _singleNode, BoolArray & _alwaysHoistMatches, bool _groupedChildIterators)
  1842. : EclHoistLocator(_originalMatches, _matches, _singleNode, _alwaysHoistMatches), selectors(_selectors), groupedChildIterators(_groupedChildIterators)
  1843. {
  1844. original = _original;
  1845. okToSelect = false;
  1846. gathered = false;
  1847. conditionalDepth = 0;
  1848. executedOnce = false;
  1849. switch (original->getOperator())
  1850. {
  1851. case no_call:
  1852. case no_externalcall:
  1853. case no_libraryscopeinstance:
  1854. okToSelect = true;
  1855. break;
  1856. }
  1857. }
  1858. void findSplitPoints(IHqlExpression * expr, unsigned from, unsigned to, bool _alwaysSingle, bool _executedOnce)
  1859. {
  1860. alwaysSingle = _alwaysSingle;
  1861. for (unsigned i=from; i < to; i++)
  1862. {
  1863. IHqlExpression * cur = expr->queryChild(i);
  1864. executedOnce = _executedOnce || cur->isAttribute(); // assume attributes are only executed once.
  1865. findSplitPoints(cur);
  1866. }
  1867. alwaysSingle = false;
  1868. }
  1869. protected:
  1870. void findSplitPoints(IHqlExpression * expr)
  1871. {
  1872. //containsNonActiveDataset() would be nice - but that isn't percolated outside assigns etc.
  1873. if (containsAnyDataset(expr) || containsMustHoist(expr))
  1874. {
  1875. if (!gathered)
  1876. {
  1877. gatherAmbiguousSelectors(original);
  1878. gathered = true;
  1879. }
  1880. analyse(expr, 0);
  1881. }
  1882. }
  1883. bool queryHoistDataset(IHqlExpression * ds)
  1884. {
  1885. bool alwaysHoist = true;
  1886. if (executedOnce)
  1887. {
  1888. if (conditionalDepth != 0)
  1889. alwaysHoist = false;
  1890. }
  1891. return alwaysHoist;
  1892. }
  1893. bool queryNoteDataset(IHqlExpression * ds)
  1894. {
  1895. bool alwaysHoist = queryHoistDataset(ds);
  1896. //MORE: It should be possible to remove this condition, but it causes problems with resourcing hsss.xhql amongst others -> disable for the moment
  1897. if (alwaysHoist)
  1898. noteDataset(ds, ds, alwaysHoist);
  1899. return alwaysHoist;
  1900. }
  1901. virtual void analyseExpr(IHqlExpression * expr)
  1902. {
  1903. if (alreadyVisited(expr))
  1904. return;
  1905. node_operator op = expr->getOperator();
  1906. switch (op)
  1907. {
  1908. case no_select:
  1909. //Only interested in the leftmost no_select
  1910. if (expr->hasAttribute(newAtom))
  1911. {
  1912. IHqlExpression * ds = expr->queryChild(0);
  1913. if (isEvaluateable(ds))
  1914. {
  1915. //MORE: Following isn't a very nice test - stops implicit denormalize getting messed up
  1916. if (expr->isDataset())
  1917. break;
  1918. //Debtable.....
  1919. //Don't hoist counts on indexes or dataset - it may mean they are evaluated more frequently than need be.
  1920. //If dependencies and root graphs are handled correctly this could be deleted.
  1921. if (isCompoundAggregate(ds))
  1922. break;
  1923. if (!expr->isDatarow() && !expr->isDataset() && !expr->isDictionary())
  1924. {
  1925. if (queryHoistDataset(ds))
  1926. {
  1927. noteScalar(expr, expr);
  1928. return;
  1929. }
  1930. }
  1931. else
  1932. {
  1933. if (queryNoteDataset(ds))
  1934. return;
  1935. }
  1936. }
  1937. }
  1938. break;
  1939. case no_createset:
  1940. {
  1941. IHqlExpression * ds = expr->queryChild(0);
  1942. if (isEvaluateable(ds))
  1943. {
  1944. if (queryHoistDataset(ds))
  1945. {
  1946. noteScalar(expr, expr);
  1947. //?? queryNoteDataset(ds);
  1948. return;
  1949. }
  1950. }
  1951. break;
  1952. }
  1953. case no_assign:
  1954. {
  1955. IHqlExpression * rhs = expr->queryChild(1);
  1956. //if rhs is a new, evaluatable, dataset then we want to add it
  1957. if ((rhs->isDataset() || rhs->isDictionary()) && isEvaluateable(rhs))
  1958. {
  1959. if (queryNoteDataset(rhs))
  1960. return;
  1961. }
  1962. break;
  1963. }
  1964. case no_sizeof:
  1965. case no_allnodes:
  1966. case no_nohoist:
  1967. case no_forcegraph:
  1968. return;
  1969. case no_globalscope:
  1970. case no_evalonce:
  1971. if (expr->isDataset() || expr->isDatarow() || expr->isDictionary())
  1972. noteDataset(expr, expr->queryChild(0), true);
  1973. else
  1974. noteScalar(expr, expr->queryChild(0));
  1975. return;
  1976. case no_thisnode:
  1977. throwUnexpected();
  1978. case no_getgraphresult:
  1979. if (expr->hasAttribute(_streaming_Atom) || expr->hasAttribute(_distributed_Atom))
  1980. {
  1981. noteDataset(expr, expr, true);
  1982. return;
  1983. }
  1984. break;
  1985. case no_getgraphloopresult:
  1986. noteDataset(expr, expr, true);
  1987. return;
  1988. case no_createdictionary:
  1989. if (isEvaluateable(expr) && !isConstantDictionary(expr))
  1990. noteDataset(expr, expr, true);
  1991. return;
  1992. case no_selectnth:
  1993. if (expr->queryChild(1)->isConstant())
  1994. {
  1995. IHqlExpression * ds = expr->queryChild(0);
  1996. switch (ds->getOperator())
  1997. {
  1998. case no_getgraphresult:
  1999. if (!expr->hasAttribute(_streaming_Atom) && !expr->hasAttribute(_distributed_Atom))
  2000. break;
  2001. //fallthrough
  2002. case no_getgraphloopresult:
  2003. noteDataset(expr, expr, true);
  2004. return;
  2005. }
  2006. }
  2007. break;
  2008. }
  2009. bool wasOkToSelect = okToSelect;
  2010. if (expr->isDataset())
  2011. {
  2012. switch (expr->getOperator())
  2013. {
  2014. case no_compound_diskread:
  2015. case no_compound_disknormalize:
  2016. case no_compound_diskaggregate:
  2017. case no_compound_diskcount:
  2018. case no_compound_diskgroupaggregate:
  2019. case no_compound_indexread:
  2020. case no_compound_indexnormalize:
  2021. case no_compound_indexaggregate:
  2022. case no_compound_indexcount:
  2023. case no_compound_indexgroupaggregate:
  2024. case no_compound_childread:
  2025. case no_compound_childnormalize:
  2026. case no_compound_childaggregate:
  2027. case no_compound_childcount:
  2028. case no_compound_childgroupaggregate:
  2029. case no_compound_selectnew:
  2030. case no_compound_inline:
  2031. case no_newkeyindex:
  2032. case no_keyindex:
  2033. case no_table:
  2034. okToSelect = false;
  2035. break;
  2036. }
  2037. if (okToSelect && isEvaluateable(expr))
  2038. {
  2039. if (queryNoteDataset(expr))
  2040. return;
  2041. }
  2042. }
  2043. else
  2044. okToSelect = true;
  2045. switch (op)
  2046. {
  2047. case no_if:
  2048. case no_choose:
  2049. case no_chooseds:
  2050. {
  2051. IHqlExpression * cond = expr->queryChild(0);
  2052. analyseExpr(cond);
  2053. if (expr->isDataset() || expr->isDatarow() || expr->isDictionary())
  2054. conditionalDepth++;
  2055. doAnalyseChildren(expr, 1);
  2056. if (expr->isDataset() || expr->isDatarow() || expr->isDictionary())
  2057. conditionalDepth--;
  2058. break;
  2059. }
  2060. case no_mapto:
  2061. {
  2062. analyseExpr(expr->queryChild(0));
  2063. if (expr->isDataset() || expr->isDatarow() || expr->isDictionary())
  2064. conditionalDepth++;
  2065. analyseExpr(expr->queryChild(1));
  2066. if (expr->isDataset() || expr->isDatarow() || expr->isDictionary())
  2067. conditionalDepth--;
  2068. break;
  2069. }
  2070. default:
  2071. NewHqlTransformer::analyseExpr(expr);
  2072. break;
  2073. }
  2074. okToSelect = wasOkToSelect;
  2075. }
  2076. bool isCompoundAggregate(IHqlExpression * ds)
  2077. {
  2078. return false;
  2079. //Generates worse code unless we take into account whether or not the newDisk operation flags are enabled.
  2080. if (!isTrivialSelectN(ds))
  2081. return false;
  2082. IHqlExpression * agg = ds->queryChild(0);
  2083. if (isSimpleCountAggregate(agg, true))
  2084. return true;
  2085. return false;
  2086. }
  2087. void gatherAmbiguousSelectors(IHqlExpression * expr)
  2088. {
  2089. //Horrible code to try and cope with ambiguous left selectors.
  2090. //o Tree is ambiguous so same child expression can occur in different contexts - so can't depend on the context it is found in to work out if can hoist
  2091. //o If any selector that is hidden within child expressions matches one in scope then can't hoist it.
  2092. //If the current expression creates a selector, then can't hoist anything that depends on it [only add to hidden if in selectors to reduce searching]
  2093. //o Want to hoist as much as possible.
  2094. if (selectors.empty())
  2095. return;
  2096. unsigned first = getFirstActivityArgument(expr);
  2097. unsigned last = first + getNumActivityArguments(expr);
  2098. unsigned max = expr->numChildren();
  2099. unsigned i;
  2100. HqlExprCopyArray hiddenSelectors;
  2101. for (i = 0; i < first; i++)
  2102. expr->queryChild(i)->gatherTablesUsed(&hiddenSelectors, NULL);
  2103. for (i = last; i < max; i++)
  2104. expr->queryChild(i)->gatherTablesUsed(&hiddenSelectors, NULL);
  2105. ForEachItemIn(iSel, selectors)
  2106. {
  2107. IHqlExpression & cur = selectors.item(iSel);
  2108. if (hiddenSelectors.contains(cur))
  2109. ambiguousSelectors.append(cur);
  2110. }
  2111. switch (getChildDatasetType(expr))
  2112. {
  2113. case childdataset_datasetleft:
  2114. case childdataset_left:
  2115. {
  2116. IHqlExpression * ds = expr->queryChild(0);
  2117. IHqlExpression * selSeq = querySelSeq(expr);
  2118. OwnedHqlExpr left = createSelector(no_left, ds, selSeq);
  2119. if (selectors.contains(*left))
  2120. ambiguousSelectors.append(*left);
  2121. break;
  2122. }
  2123. case childdataset_same_left_right:
  2124. case childdataset_top_left_right:
  2125. case childdataset_nway_left_right:
  2126. {
  2127. IHqlExpression * ds = expr->queryChild(0);
  2128. IHqlExpression * selSeq = querySelSeq(expr);
  2129. OwnedHqlExpr left = createSelector(no_left, ds, selSeq);
  2130. OwnedHqlExpr right = createSelector(no_right, ds, selSeq);
  2131. if (selectors.contains(*left))
  2132. ambiguousSelectors.append(*left);
  2133. if (selectors.contains(*right))
  2134. ambiguousSelectors.append(*right);
  2135. break;
  2136. }
  2137. case childdataset_leftright:
  2138. {
  2139. IHqlExpression * leftDs = expr->queryChild(0);
  2140. IHqlExpression * rightDs = expr->queryChild(1);
  2141. IHqlExpression * selSeq = querySelSeq(expr);
  2142. OwnedHqlExpr left = createSelector(no_left, leftDs, selSeq);
  2143. OwnedHqlExpr right = createSelector(no_right, rightDs, selSeq);
  2144. if (selectors.contains(*left))
  2145. ambiguousSelectors.append(*left);
  2146. if (selectors.contains(*right))
  2147. ambiguousSelectors.append(*right);
  2148. break;
  2149. }
  2150. }
  2151. }
  2152. bool isEvaluateable(IHqlExpression * ds, bool ignoreInline = false)
  2153. {
  2154. //Don't hoist an alias - it could create unnecessary duplicate spills - hoist its input
  2155. if (ds->getOperator() == no_dataset_alias)
  2156. return false;
  2157. //Not allowed to hoist
  2158. if (isContextDependent(ds, (conditionalDepth == 0), true))
  2159. return false;
  2160. //MORE: Needs more work for child queries - need a GroupedChildIterator activity
  2161. if (isGrouped(ds) && selectors.ordinality() && !groupedChildIterators)
  2162. return false;
  2163. //Check datasets are available
  2164. HqlExprCopyArray scopeUsed;
  2165. ds->gatherTablesUsed(NULL, &scopeUsed);
  2166. ForEachItemIn(i, scopeUsed)
  2167. {
  2168. IHqlExpression & cur = scopeUsed.item(i);
  2169. if (!selectors.contains(cur))
  2170. return false;
  2171. if (ambiguousSelectors.contains(cur))
  2172. return false;
  2173. }
  2174. if (!isEfficientToHoistDataset(ds, ignoreInline))
  2175. return false;
  2176. return true;
  2177. }
  2178. bool isEfficientToHoistDataset(IHqlExpression * ds, bool ignoreInline) const
  2179. {
  2180. //MORE: This whole function could do with some significant improvements. Whether it is inefficient to hoist
  2181. //depends on at least the following...
  2182. //a) cost of serializing v cost of re-evaluating (which can depend on the engine).
  2183. //b) How many times it will be evaluated in the child context
  2184. if (ds->getOperator() == no_createdictionary)
  2185. return true;
  2186. if (isInlineTrivialDataset(ds))
  2187. return false;
  2188. #ifdef MINIMAL_CHANGES
  2189. if (!ignoreInline)
  2190. {
  2191. //Generally this appears to be better to hoist since it involves calling a transform.
  2192. if (ds->getOperator() == no_dataset_from_transform)
  2193. return true;
  2194. if (canProcessInline(NULL, ds))
  2195. return false;
  2196. }
  2197. #endif
  2198. return true;
  2199. }
  2200. protected:
  2201. IHqlExpression * original;
  2202. HqlExprCopyArray & selectors;
  2203. HqlExprCopyArray ambiguousSelectors;
  2204. unsigned conditionalDepth;
  2205. bool okToSelect;
  2206. bool gathered;
  2207. bool groupedChildIterators;
  2208. bool executedOnce;
  2209. };
  2210. void EclResourcer::gatherChildSplitPoints(IHqlExpression * expr, BoolArray & alwaysHoistChild, ResourcerInfo * info, unsigned first, unsigned last)
  2211. {
  2212. //NB: Don't call member functions to ensure correct nesting of transform mutexes.
  2213. EclChildSplitPointLocator locator(expr, activeSelectors, info->originalChildDependents, info->childDependents, info->childSingleNode, alwaysHoistChild, options.groupedChildIterators);
  2214. unsigned max = expr->numChildren();
  2215. //If child queries are supported then don't hoist the expressions if they might only be evaluated once
  2216. //because they may be conditional
  2217. switch (expr->getOperator())
  2218. {
  2219. case no_setresult:
  2220. case no_selectnth:
  2221. //set results, only done once=>don't hoist conditionals
  2222. locator.findSplitPoints(expr, last, max, true, true);
  2223. return;
  2224. case no_loop:
  2225. if ((options.targetClusterType == ThorLCRCluster) && !options.isChildQuery)
  2226. {
  2227. //This is ugly! The body is executed in parallel, so don't force that as a work unit result
  2228. //It means some child query expressions within loops don't get forced into work unit writes
  2229. //but that just means that the generated code will be not as good as it could be.
  2230. const unsigned bodyArg = 4;
  2231. locator.findSplitPoints(expr, 1, bodyArg, true, false);
  2232. locator.findSplitPoints(expr, bodyArg, bodyArg+1, false, false);
  2233. locator.findSplitPoints(expr, bodyArg+1, max, true, false);
  2234. return;
  2235. }
  2236. break;
  2237. }
  2238. locator.findSplitPoints(expr, 0, first, true, true); // IF() conditions only evaluated once... => don't force
  2239. locator.findSplitPoints(expr, last, max, true, false);
  2240. }
  2241. class EclThisNodeLocator : public EclHoistLocator
  2242. {
  2243. public:
  2244. EclThisNodeLocator(HqlExprCopyArray & _originalMatches, HqlExprArray & _matches, BoolArray & _singleNode, BoolArray & _alwaysHoistMatches)
  2245. : EclHoistLocator(_originalMatches, _matches, _singleNode, _alwaysHoistMatches)
  2246. {
  2247. allNodesDepth = 0;
  2248. }
  2249. protected:
  2250. virtual void analyseExpr(IHqlExpression * expr)
  2251. {
  2252. //NB: This doesn't really work for no_thisnode occurring in multiple contexts. We should probably hoist it from everywhere if it is hoistable from anywhere,
  2253. // although theoretically that gives us problems with ambiguous selectors.
  2254. if (alreadyVisited(expr) || !containsThisNode(expr))
  2255. return;
  2256. node_operator op = expr->getOperator();
  2257. switch (op)
  2258. {
  2259. case no_allnodes:
  2260. allNodesDepth++;
  2261. NewHqlTransformer::analyseExpr(expr);
  2262. allNodesDepth--;
  2263. return;
  2264. case no_thisnode:
  2265. if (allNodesDepth == 0)
  2266. {
  2267. if (expr->isDataset() || expr->isDatarow() || expr->isDictionary())
  2268. noteDataset(expr, expr->queryChild(0), true);
  2269. else
  2270. noteScalar(expr, expr->queryChild(0));
  2271. return;
  2272. }
  2273. allNodesDepth--;
  2274. NewHqlTransformer::analyseExpr(expr);
  2275. allNodesDepth++;
  2276. return;
  2277. }
  2278. NewHqlTransformer::analyseExpr(expr);
  2279. }
  2280. protected:
  2281. unsigned allNodesDepth;
  2282. };
  2283. static bool isPotentialCompoundSteppedIndexRead(IHqlExpression * expr)
  2284. {
  2285. loop
  2286. {
  2287. switch (expr->getOperator())
  2288. {
  2289. case no_compound_diskread:
  2290. case no_compound_disknormalize:
  2291. case no_compound_diskaggregate:
  2292. case no_compound_diskcount:
  2293. case no_compound_diskgroupaggregate:
  2294. case no_compound_childread:
  2295. case no_compound_childnormalize:
  2296. case no_compound_childaggregate:
  2297. case no_compound_childcount:
  2298. case no_compound_childgroupaggregate:
  2299. case no_compound_selectnew:
  2300. case no_compound_inline:
  2301. return false;
  2302. case no_compound_indexread:
  2303. case no_newkeyindex:
  2304. return true;
  2305. case no_getgraphloopresult:
  2306. return true; // Could be an index read in another graph iteration, so don't combine
  2307. case no_keyedlimit:
  2308. case no_preload:
  2309. case no_filter:
  2310. case no_hqlproject:
  2311. case no_newusertable:
  2312. case no_limit:
  2313. case no_sorted:
  2314. case no_preservemeta:
  2315. case no_distributed:
  2316. case no_grouped:
  2317. case no_stepped:
  2318. case no_section:
  2319. case no_sectioninput:
  2320. case no_dataset_alias:
  2321. break;
  2322. case no_choosen:
  2323. {
  2324. IHqlExpression * arg2 = expr->queryChild(2);
  2325. if (arg2 && !arg2->isPure())
  2326. return false;
  2327. break;
  2328. }
  2329. default:
  2330. return false;
  2331. }
  2332. expr = expr->queryChild(0);
  2333. }
  2334. }
  2335. bool EclResourcer::findSplitPoints(IHqlExpression * expr)
  2336. {
  2337. ResourcerInfo * info = queryResourceInfo(expr);
  2338. bool savedInsideNeverSplit = insideNeverSplit;
  2339. bool savedInsideSteppedNeverSplit = insideSteppedNeverSplit;
  2340. if (insideSteppedNeverSplit && info)
  2341. {
  2342. if (!isPotentialCompoundSteppedIndexRead(expr) && (expr->getOperator() != no_datasetlist))
  2343. insideSteppedNeverSplit = false;
  2344. }
  2345. if (info && info->numUses)
  2346. {
  2347. if (insideNeverSplit || insideSteppedNeverSplit)
  2348. info->neverSplit = true;
  2349. if (info->isAlreadyInScope && (info->numUses == 0) && expr->isDatarow())
  2350. {
  2351. // A row is already bound to a temporary
  2352. info->isActivity = true;
  2353. info->containsActivity = true;
  2354. info->numUses++;
  2355. //More: May need to force child activities to not be resourced (e.g., if somehow visited via another path)
  2356. //info->preserve = true;
  2357. return info->containsActivity;
  2358. }
  2359. if (info->isAlreadyInScope || info->isActivity || !info->containsActivity)
  2360. {
  2361. info->numUses++;
  2362. return info->containsActivity;
  2363. }
  2364. }
  2365. else
  2366. {
  2367. info = queryCreateResourceInfo(expr);
  2368. info->numUses++;
  2369. if (insideNeverSplit || insideSteppedNeverSplit)
  2370. info->neverSplit = true;
  2371. bool isActivity = true;
  2372. switch (expr->getOperator())
  2373. {
  2374. case no_select:
  2375. //either a select from a setresult or use of a child-dataset
  2376. if (isNewSelector(expr))
  2377. {
  2378. info->containsActivity = findSplitPoints(expr->queryChild(0));
  2379. assertex(queryResourceInfo(expr->queryChild(0))->isActivity);
  2380. }
  2381. if (expr->isDataset() || expr->isDatarow())
  2382. {
  2383. info->isActivity = true;
  2384. info->containsActivity = true;
  2385. }
  2386. return info->containsActivity;
  2387. case no_mapto:
  2388. throwUnexpected();
  2389. info->containsActivity = findSplitPoints(expr->queryChild(1));
  2390. return info->containsActivity;
  2391. case no_activerow:
  2392. info->isActivity = true;
  2393. info->containsActivity = false;
  2394. return false;
  2395. case no_attr:
  2396. case no_attr_expr:
  2397. case no_attr_link:
  2398. case no_rowset: // don't resource this as an activity
  2399. case no_getgraphloopresultset:
  2400. info->isActivity = false;
  2401. info->containsActivity = false;
  2402. return false;
  2403. case no_datasetlist:
  2404. isActivity = false;
  2405. break;
  2406. case no_rowsetrange:
  2407. {
  2408. //Don't resource this as an activity if it is a function of the input graph rows,
  2409. //however we do want to if it is coming from a dataset list.
  2410. IHqlExpression * ds = expr->queryChild(0);
  2411. //MORE: Should walk further down the tree to allow for nested rowsetranges etc.
  2412. if (ds->getOperator() == no_rowset || ds->getOperator() == no_getgraphloopresultset)
  2413. {
  2414. info->isActivity = false;
  2415. info->containsActivity = false;
  2416. return false;
  2417. }
  2418. isActivity = false;
  2419. break;
  2420. }
  2421. case no_keyedlimit:
  2422. if (options.preventKeyedSplit)
  2423. insideNeverSplit = true;
  2424. break;
  2425. case no_filter:
  2426. if (options.preventKeyedSplit && filterIsKeyed(expr))
  2427. insideNeverSplit = true;
  2428. else
  2429. {
  2430. LinkedHqlExpr invariant;
  2431. OwnedHqlExpr cond = extractFilterConditions(invariant, expr, expr->queryNormalizedSelector(), false);
  2432. if (invariant)
  2433. info->isConditionalFilter = true;
  2434. }
  2435. break;
  2436. case no_hqlproject:
  2437. case no_newusertable:
  2438. case no_aggregate:
  2439. case no_newaggregate:
  2440. if (options.preventKeyedSplit && expr->hasAttribute(keyedAtom))
  2441. insideNeverSplit = true;
  2442. break;
  2443. case no_stepped:
  2444. case no_mergejoin:
  2445. case no_nwayjoin:
  2446. if (options.preventSteppedSplit)
  2447. insideSteppedNeverSplit = true;
  2448. break;
  2449. case no_compound_diskread:
  2450. case no_compound_disknormalize:
  2451. case no_compound_diskaggregate:
  2452. case no_compound_diskcount:
  2453. case no_compound_diskgroupaggregate:
  2454. case no_compound_indexread:
  2455. case no_compound_indexnormalize:
  2456. case no_compound_indexaggregate:
  2457. case no_compound_indexcount:
  2458. case no_compound_indexgroupaggregate:
  2459. case no_compound_childread:
  2460. case no_compound_childnormalize:
  2461. case no_compound_childaggregate:
  2462. case no_compound_childcount:
  2463. case no_compound_childgroupaggregate:
  2464. case no_compound_selectnew:
  2465. case no_compound_inline:
  2466. insideNeverSplit = true;
  2467. break;
  2468. }
  2469. ITypeInfo * type = expr->queryType();
  2470. if (!type || type->isScalar())
  2471. {
  2472. insideNeverSplit = savedInsideNeverSplit;
  2473. insideSteppedNeverSplit = savedInsideSteppedNeverSplit;
  2474. return false;
  2475. }
  2476. info->isActivity = isActivity;
  2477. info->containsActivity = true;
  2478. }
  2479. unsigned first = getFirstActivityArgument(expr);
  2480. unsigned last = first + getNumActivityArguments(expr);
  2481. if (options.hoistResourced)
  2482. {
  2483. BoolArray alwaysHoistChild;
  2484. switch (expr->getOperator())
  2485. {
  2486. case no_allnodes:
  2487. {
  2488. //MORE: This needs to recursively walk and lift any contained no_selfnode, but don't go past another nested no_allnodes;
  2489. EclThisNodeLocator locator(info->originalChildDependents, info->childDependents, info->childSingleNode, alwaysHoistChild);
  2490. locator.analyseChild(expr->queryChild(0), true);
  2491. break;
  2492. }
  2493. case no_childquery:
  2494. throwUnexpected();
  2495. default:
  2496. {
  2497. for (unsigned idx=first; idx < last; idx++)
  2498. {
  2499. IHqlExpression * cur = expr->queryChild(idx);
  2500. findSplitPoints(cur);
  2501. }
  2502. insideNeverSplit = savedInsideNeverSplit;
  2503. insideSteppedNeverSplit = savedInsideSteppedNeverSplit;
  2504. gatherChildSplitPoints(expr, alwaysHoistChild, info, first, last);
  2505. break;
  2506. }
  2507. }
  2508. insideNeverSplit = false;
  2509. insideSteppedNeverSplit = false;
  2510. ForEachItemIn(i2, info->childDependents)
  2511. {
  2512. IHqlExpression & cur = info->childDependents.item(i2);
  2513. if (alwaysHoistChild.item(i2))
  2514. findSplitPoints(&cur);
  2515. else
  2516. conditionalChildren.append(cur);
  2517. }
  2518. }
  2519. else
  2520. {
  2521. for (unsigned idx=first; idx < last; idx++)
  2522. findSplitPoints(expr->queryChild(idx));
  2523. }
  2524. insideNeverSplit = savedInsideNeverSplit;
  2525. insideSteppedNeverSplit = savedInsideSteppedNeverSplit;
  2526. return info->containsActivity;
  2527. }
  2528. void EclResourcer::findSplitPoints(HqlExprArray & exprs)
  2529. {
  2530. ForEachItemIn(idx, exprs)
  2531. findSplitPoints(&exprs.item(idx));
  2532. extendSplitPoints();
  2533. }
  2534. void EclResourcer::extendSplitPoints()
  2535. {
  2536. for (unsigned i=0; i < conditionalChildren.ordinality(); i++)
  2537. {
  2538. IHqlExpression & cur = conditionalChildren.item(i);
  2539. if (isWorthForcingHoist(&cur))
  2540. findSplitPoints(&cur);
  2541. }
  2542. }
  2543. //------------------------------------------------------------------------------------------
  2544. // PASS2: Actually create the subgraphs based on splitters.
  2545. void EclResourcer::createInitialGraph(IHqlExpression * expr, IHqlExpression * owner, ResourceGraphInfo * ownerGraph, LinkKind linkKind, bool forceNewGraph)
  2546. {
  2547. ResourcerInfo * info = queryResourceInfo(expr);
  2548. if (!info || !info->containsActivity)
  2549. return;
  2550. LinkKind childLinkKind = UnconditionalLink;
  2551. Linked<ResourceGraphInfo> thisGraph = ownerGraph;
  2552. bool forceNewChildGraph = false;
  2553. if (info->isActivity)
  2554. {
  2555. //Need to ensure no_libraryselects are not separated from the no_libraryscopeinstance
  2556. //so ensure they are placed in the same graph.
  2557. node_operator op = expr->getOperator();
  2558. if (op == no_libraryselect)
  2559. {
  2560. ResourcerInfo * moduleInfo = queryResourceInfo(expr->queryChild(1));
  2561. if (!info->graph && moduleInfo->graph)
  2562. info->graph.set(moduleInfo->graph);
  2563. }
  2564. if (info->graph)
  2565. {
  2566. connectGraphs(info->graph, expr, ownerGraph, owner, linkKind);
  2567. info->numExternalUses++;
  2568. return;
  2569. }
  2570. unsigned numUses = info->numUses;
  2571. switch (op)
  2572. {
  2573. case no_libraryscopeinstance:
  2574. numUses = 1;
  2575. break;
  2576. case no_libraryselect:
  2577. forceNewGraph = true;
  2578. break;
  2579. }
  2580. if (!ownerGraph || numUses > 1 || (linkKind != UnconditionalLink) || forceNewGraph)
  2581. {
  2582. thisGraph.setown(createGraph());
  2583. connectGraphs(thisGraph, expr, ownerGraph, owner, linkKind);
  2584. info->numExternalUses++;
  2585. if (!ownerGraph && sequential)
  2586. thisGraph->hasSequentialSource = true;
  2587. }
  2588. info->graph.set(thisGraph);
  2589. switch (expr->getOperator())
  2590. {
  2591. case no_compound:
  2592. //NB: First argument is forced into a separate graph
  2593. createInitialGraph(expr->queryChild(0), expr, NULL, UnconditionalLink, true);
  2594. createInitialGraph(expr->queryChild(1), expr, thisGraph, UnconditionalLink, false);
  2595. return;
  2596. case no_executewhen:
  2597. {
  2598. bool newGraph = expr->isAction() && (options.targetClusterType == HThorCluster);
  2599. createInitialGraph(expr->queryChild(0), expr, thisGraph, UnconditionalLink, newGraph);
  2600. createInitialGraph(expr->queryChild(1), expr, thisGraph, UnconditionalLink, true);
  2601. return;
  2602. }
  2603. case no_keyindex:
  2604. case no_newkeyindex:
  2605. return;
  2606. case no_parallel:
  2607. {
  2608. ForEachChild(i, expr)
  2609. createInitialGraph(expr->queryChild(i), expr, thisGraph, UnconditionalLink, true);
  2610. return;
  2611. }
  2612. case no_if:
  2613. case no_choose:
  2614. case no_chooseds:
  2615. //conditional nodes, the child branches are marked as conditional
  2616. childLinkKind = UnconditionalLink;
  2617. thisGraph->mergedConditionSource = true;
  2618. if (!options.noConditionalLinks || expr->isAction())
  2619. forceNewChildGraph = true;
  2620. break;
  2621. case no_filter:
  2622. if (info->isConditionalFilter)
  2623. {
  2624. thisGraph->mergedConditionSource = true;
  2625. if (!options.noConditionalLinks)
  2626. forceNewChildGraph = true;
  2627. }
  2628. break;
  2629. // case no_nonempty:
  2630. case no_sequential:
  2631. {
  2632. unsigned first = getFirstActivityArgument(expr);
  2633. unsigned last = first + getNumActivityArguments(expr);
  2634. createInitialGraph(expr->queryChild(first), expr, thisGraph, SequenceLink, true);
  2635. for (unsigned idx = first+1; idx < last; idx++)
  2636. createInitialGraph(expr->queryChild(idx), expr, thisGraph, SequenceLink, true);
  2637. return;
  2638. }
  2639. case no_case:
  2640. case no_map:
  2641. {
  2642. throwUnexpected();
  2643. }
  2644. case no_output:
  2645. {
  2646. //Tag the inputs to an output statement, so that if a spill was going to occur we read
  2647. //from the output file instead of spilling.
  2648. //Needs the grouping to be saved in the same way. Could cope with compressed matching, but not
  2649. //much point - since fairly unlikely.
  2650. IHqlExpression * filename = expr->queryChild(1);
  2651. if (filename && (filename->getOperator() == no_constant) && !expr->hasAttribute(xmlAtom) && !expr->hasAttribute(csvAtom))
  2652. {
  2653. IHqlExpression * dataset = expr->queryChild(0);
  2654. if (expr->hasAttribute(groupedAtom) == (dataset->queryType()->queryGroupInfo() != NULL))
  2655. {
  2656. StringBuffer filenameText;
  2657. filename->queryValue()->getStringValue(filenameText);
  2658. ResourcerInfo * childInfo = queryResourceInfo(dataset);
  2659. if (!childInfo->linkedFromChild && !isUpdatedConditionally(expr))
  2660. childInfo->outputToUseForSpill = expr;
  2661. }
  2662. }
  2663. if (isUpdatedConditionally(expr))
  2664. thisGraph->mergedConditionSource = true;
  2665. break;
  2666. }
  2667. case no_buildindex:
  2668. if (isUpdatedConditionally(expr))
  2669. thisGraph->mergedConditionSource = true;
  2670. break;
  2671. }
  2672. }
  2673. unsigned first = getFirstActivityArgument(expr);
  2674. unsigned last = first + getNumActivityArguments(expr);
  2675. for (unsigned idx = first; idx < last; idx++)
  2676. createInitialGraph(expr->queryChild(idx), expr, thisGraph, childLinkKind, forceNewChildGraph);
  2677. ForEachItemIn(i2, info->childDependents)
  2678. {
  2679. IHqlExpression & cur = info->childDependents.item(i2);
  2680. if (isResourcedActivity(&cur))
  2681. createInitialGraph(&cur, expr, thisGraph, SequenceLink, true);
  2682. }
  2683. }
  2684. void EclResourcer::createInitialGraphs(HqlExprArray & exprs)
  2685. {
  2686. ForEachItemIn(idx, exprs)
  2687. createInitialGraph(&exprs.item(idx), NULL, NULL, UnconditionalLink, false);
  2688. }
  2689. void EclResourcer::createInitialRemoteGraph(IHqlExpression * expr, IHqlExpression * owner, ResourceGraphInfo * ownerGraph, bool forceNewGraph)
  2690. {
  2691. ResourcerInfo * info = queryResourceInfo(expr);
  2692. if (!info || !info->containsActivity)
  2693. return;
  2694. Linked<ResourceGraphInfo> thisGraph = ownerGraph;
  2695. if (info->isActivity)
  2696. {
  2697. if (info->graph)
  2698. {
  2699. connectGraphs(info->graph, expr, ownerGraph, owner, UnconditionalLink);
  2700. info->numExternalUses++;
  2701. return;
  2702. }
  2703. if (!ownerGraph || forceNewGraph)
  2704. {
  2705. thisGraph.setown(createGraph());
  2706. connectGraphs(thisGraph, expr, ownerGraph, owner, UnconditionalLink);
  2707. info->numExternalUses++;
  2708. }
  2709. info->graph.set(thisGraph);
  2710. switch (expr->getOperator())
  2711. {
  2712. case no_compound:
  2713. createInitialRemoteGraph(expr->queryChild(0), expr, NULL, true);
  2714. createInitialRemoteGraph(expr->queryChild(1), expr, thisGraph, false);
  2715. return;
  2716. case no_executewhen:
  2717. createInitialRemoteGraph(expr->queryChild(0), expr, thisGraph, false);
  2718. createInitialRemoteGraph(expr->queryChild(1), expr, thisGraph, true);
  2719. return;
  2720. }
  2721. }
  2722. unsigned first = getFirstActivityArgument(expr);
  2723. unsigned last = first + getNumActivityArguments(expr);
  2724. for (unsigned idx = first; idx < last; idx++)
  2725. createInitialRemoteGraph(expr->queryChild(idx), expr, thisGraph, false);
  2726. }
  2727. void EclResourcer::createInitialRemoteGraphs(HqlExprArray & exprs)
  2728. {
  2729. ForEachItemIn(idx, exprs)
  2730. createInitialRemoteGraph(&exprs.item(idx), NULL, NULL, false);
  2731. }
  2732. //------------------------------------------------------------------------------------------
  2733. // PASS3: Tag graphs/links that are conditional or unconditional
  2734. void EclResourcer::markChildDependentsAsUnconditional(ResourcerInfo * info, IHqlExpression * condition)
  2735. {
  2736. if (options.hoistResourced)
  2737. {
  2738. ForEachItemIn(i2, info->childDependents)
  2739. {
  2740. IHqlExpression & cur = info->childDependents.item(i2);
  2741. if (isResourcedActivity(&cur))
  2742. markAsUnconditional(&cur, NULL, condition);
  2743. }
  2744. }
  2745. }
  2746. void EclResourcer::markAsUnconditional(IHqlExpression * expr, ResourceGraphInfo * ownerGraph, IHqlExpression * condition)
  2747. {
  2748. ResourcerInfo * info = queryResourceInfo(expr);
  2749. if (!info || !info->containsActivity)
  2750. return;
  2751. if (!info->isActivity)
  2752. {
  2753. unsigned first = getFirstActivityArgument(expr);
  2754. unsigned last = first + getNumActivityArguments(expr);
  2755. for (unsigned idx=first; idx < last; idx++)
  2756. markAsUnconditional(expr->queryChild(idx), ownerGraph, condition);
  2757. return;
  2758. }
  2759. if (condition)
  2760. if (info->addCondition(condition))
  2761. condition = NULL;
  2762. if (info->pathToExpr == ResourcerInfo::PathUnconditional)
  2763. return;
  2764. if ((info->pathToExpr == ResourcerInfo::PathConditional) && condition)
  2765. {
  2766. if (targetClusterType == RoxieCluster)
  2767. {
  2768. if (spillMultiCondition)
  2769. {
  2770. if (info->graph != ownerGraph)
  2771. info->graph->isUnconditional = true;
  2772. }
  2773. return;
  2774. }
  2775. else
  2776. {
  2777. if (info->graph != ownerGraph)
  2778. return;
  2779. }
  2780. }
  2781. bool wasConditional = (info->pathToExpr == ResourcerInfo::PathConditional);
  2782. if (!condition)
  2783. {
  2784. info->pathToExpr = ResourcerInfo::PathUnconditional;
  2785. if (info->graph != ownerGraph)
  2786. info->graph->isUnconditional = true;
  2787. }
  2788. else
  2789. info->pathToExpr = ResourcerInfo::PathConditional;
  2790. node_operator op = expr->getOperator();
  2791. switch (op)
  2792. {
  2793. case no_if:
  2794. case no_choose:
  2795. case no_chooseds:
  2796. if (options.noConditionalLinks)
  2797. break;
  2798. if (condition)
  2799. markCondition(expr, condition, wasConditional);
  2800. else
  2801. {
  2802. //This list is processed in a second phase.
  2803. if (rootConditions.find(*expr) == NotFound)
  2804. rootConditions.append(*LINK(expr));
  2805. }
  2806. markChildDependentsAsUnconditional(info, condition);
  2807. return;
  2808. case no_filter:
  2809. if (!info->isConditionalFilter || options.noConditionalLinks)
  2810. break;
  2811. if (condition)
  2812. markCondition(expr, condition, wasConditional);
  2813. else
  2814. {
  2815. //This list is processed in a second phase.
  2816. if (rootConditions.find(*expr) == NotFound)
  2817. rootConditions.append(*LINK(expr));
  2818. }
  2819. markChildDependentsAsUnconditional(info, condition);
  2820. return;
  2821. case no_sequential:
  2822. // case no_nonempty:
  2823. if (!options.isChildQuery)
  2824. {
  2825. unsigned first = getFirstActivityArgument(expr);
  2826. unsigned last = first + getNumActivityArguments(expr);
  2827. IHqlExpression * child0 = expr->queryChild(0);
  2828. markAsUnconditional(child0, info->graph, condition);
  2829. queryResourceInfo(child0)->graph->hasConditionSource = true; // force it to generate even if contains something very simple e.g., null action
  2830. for (unsigned idx = first+1; idx < last; idx++)
  2831. {
  2832. OwnedHqlExpr tag = createAttribute(instanceAtom, LINK(expr), getSizetConstant(idx), LINK(condition));
  2833. IHqlExpression * child = expr->queryChild(idx);
  2834. markAsUnconditional(child, queryResourceInfo(child)->graph, tag);
  2835. queryResourceInfo(child)->setConditionSource(tag, !wasConditional);
  2836. }
  2837. markChildDependentsAsUnconditional(info, condition);
  2838. return;
  2839. }
  2840. break;
  2841. case no_case:
  2842. case no_map:
  2843. UNIMPLEMENTED;
  2844. }
  2845. unsigned first = getFirstActivityArgument(expr);
  2846. unsigned last = first + getNumActivityArguments(expr);
  2847. for (unsigned idx=first; idx < last; idx++)
  2848. markAsUnconditional(expr->queryChild(idx), info->graph, condition);
  2849. markChildDependentsAsUnconditional(info, condition);
  2850. }
  2851. void EclResourcer::markConditionBranch(unsigned childIndex, IHqlExpression * expr, IHqlExpression * condition, bool wasConditional)
  2852. {
  2853. IHqlExpression * child = queryRealChild(expr, childIndex);
  2854. if (child)
  2855. {
  2856. OwnedHqlExpr tag;
  2857. if (expr->getOperator() == no_if)
  2858. tag.setown(createAttribute(((childIndex==1) ? trueAtom : falseAtom), LINK(expr), LINK(condition)));
  2859. else
  2860. tag.setown(createAttribute(trueAtom, LINK(expr), LINK(condition), getSizetConstant(childIndex)));
  2861. markAsUnconditional(child, queryResourceInfo(child)->graph, tag);
  2862. queryResourceInfo(child)->setConditionSource(tag, !wasConditional);
  2863. }
  2864. }
  2865. void EclResourcer::markCondition(IHqlExpression * expr, IHqlExpression * condition, bool wasConditional)
  2866. {
  2867. if (expr->getOperator() == no_filter)
  2868. {
  2869. markConditionBranch(0, expr, condition, wasConditional);
  2870. }
  2871. else
  2872. {
  2873. ForEachChildFrom(i, expr, 1)
  2874. markConditionBranch(i, expr, condition, wasConditional);
  2875. }
  2876. }
  2877. void EclResourcer::markConditions(HqlExprArray & exprs)
  2878. {
  2879. ForEachItemIn(idx, exprs)
  2880. markAsUnconditional(&exprs.item(idx), NULL, NULL);
  2881. ForEachItemIn(idx2, rootConditions)
  2882. markCondition(&rootConditions.item(idx2), NULL, false);
  2883. }
  2884. //------------------------------------------------------------------------------------------
  2885. // PASS4: Split subgraphs based on resource requirements for activities
  2886. //This will need to be improved if we allow backtracking to get the best combination of activities to fit in the subgraph
  2887. void EclResourcer::createResourceSplit(IHqlExpression * expr, IHqlExpression * owner, ResourceGraphInfo * ownerNewGraph, ResourceGraphInfo * originalGraph)
  2888. {
  2889. ResourcerInfo * info = queryResourceInfo(expr);
  2890. info->graph.setown(createGraph());
  2891. info->graph->isUnconditional = originalGraph->isUnconditional;
  2892. changeGraph(expr, info->graph);
  2893. connectGraphs(info->graph, expr, ownerNewGraph, owner, UnconditionalLink);
  2894. info->numExternalUses++;
  2895. }
  2896. void EclResourcer::getResources(IHqlExpression * expr, CResources & exprResources)
  2897. {
  2898. ::getResources(expr, exprResources, options);
  2899. }
  2900. bool EclResourcer::calculateResourceSpillPoints(IHqlExpression * expr, ResourceGraphInfo * graph, CResources & resourcesSoFar, bool hasGoodSpillPoint, bool canSpill)
  2901. {
  2902. ResourcerInfo * info = queryResourceInfo(expr);
  2903. if (!info || !info->containsActivity)
  2904. return true;
  2905. if (!info->isActivity)
  2906. {
  2907. unsigned first = getFirstActivityArgument(expr);
  2908. unsigned last = first + getNumActivityArguments(expr);
  2909. if (last - first == 1)
  2910. return calculateResourceSpillPoints(expr->queryChild(first), graph, resourcesSoFar, hasGoodSpillPoint, canSpill);
  2911. for (unsigned idx = first; idx < last; idx++)
  2912. calculateResourceSpillPoints(expr->queryChild(idx), graph, resourcesSoFar, false, canSpill);
  2913. return true;
  2914. }
  2915. if (info->graph != graph)
  2916. return true;
  2917. CResources exprResources(clusterSize);
  2918. getResources(expr, exprResources);
  2919. info->isSpillPoint = false;
  2920. Owned<CResources> curResources = LINK(&resourcesSoFar);
  2921. if (resourcesSoFar.addExceeds(exprResources, *resourceLimit))
  2922. {
  2923. if (hasGoodSpillPoint)
  2924. return false;
  2925. info->isSpillPoint = true;
  2926. spilled = true;
  2927. curResources.setown(new CResources(clusterSize));
  2928. if (exprResources.exceeds(*resourceLimit))
  2929. throwError2(HQLERR_CannotResourceActivity, getOpString(expr->getOperator()), clusterSize);
  2930. }
  2931. if (options.minimizeSkewBeforeSpill)
  2932. {
  2933. if (canSpill && heavyweightAndReducesSizeOrSkew(expr))
  2934. {
  2935. //if the input activity is going to cause us to run out of resources, then it is going to be better to split here than anywhere else
  2936. //this code may conceivably cause extra spills far away because the hash distributes are moved.
  2937. IHqlExpression * childExpr = expr->queryChild(0);
  2938. ResourcerInfo * childInfo = queryResourceInfo(childExpr);
  2939. if (childInfo->graph == graph)
  2940. {
  2941. CResources childResources(clusterSize);
  2942. getResources(childExpr, childResources);
  2943. childResources.add(exprResources);
  2944. if (curResources->addExceeds(childResources, *resourceLimit))
  2945. {
  2946. info->isSpillPoint = true;
  2947. spilled = true;
  2948. calculateResourceSpillPoints(childExpr, graph, exprResources, false, true);
  2949. return true;
  2950. }
  2951. }
  2952. //otherwise continue as normal.
  2953. }
  2954. }
  2955. curResources->add(exprResources);
  2956. unsigned first = getFirstActivityArgument(expr);
  2957. unsigned last = first + getNumActivityArguments(expr);
  2958. if (hasGoodSpillPoint)
  2959. {
  2960. if (exprResources.resource[RESheavy] || exprResources.resource[REShashdist] || last-first != 1)
  2961. hasGoodSpillPoint = false;
  2962. }
  2963. else if (!info->isSpillPoint && canSpill)
  2964. {
  2965. if (lightweightAndReducesDatasetSize(expr) || queryHint(expr, spillAtom))
  2966. {
  2967. CResources savedResources(*curResources);
  2968. if (!calculateResourceSpillPoints(expr->queryChild(0), graph, *curResources, true, true))
  2969. {
  2970. curResources->set(savedResources);
  2971. info->isSpillPoint = true;
  2972. spilled = true;
  2973. calculateResourceSpillPoints(expr->queryChild(0), graph, exprResources, false, true);
  2974. }
  2975. return true;
  2976. }
  2977. }
  2978. node_operator op = expr->getOperator();
  2979. if ((op == no_if) || (op == no_choose) || (op == no_chooseds))
  2980. {
  2981. //For conditions, spill on intersection of resources used, not union.
  2982. CResources savedResources(*curResources);
  2983. if (!calculateResourceSpillPoints(expr->queryChild(1), graph, *curResources, hasGoodSpillPoint, true))
  2984. return false;
  2985. ForEachChildFrom(i, expr, 2)
  2986. {
  2987. if (expr->queryChild(i)->isAttribute())
  2988. continue;
  2989. if (!calculateResourceSpillPoints(expr->queryChild(i), graph, savedResources, hasGoodSpillPoint, true))
  2990. return false;
  2991. curResources->maximize(savedResources);
  2992. }
  2993. }
  2994. else
  2995. {
  2996. for (unsigned idx = first; idx < last; idx++)
  2997. if (!calculateResourceSpillPoints(expr->queryChild(idx), graph, *curResources, hasGoodSpillPoint, true))
  2998. return false;
  2999. }
  3000. return true;
  3001. }
  3002. void EclResourcer::insertResourceSpillPoints(IHqlExpression * expr, IHqlExpression * owner, ResourceGraphInfo * ownerOriginalGraph, ResourceGraphInfo * ownerNewGraph)
  3003. {
  3004. ResourcerInfo * info = queryResourceInfo(expr);
  3005. if (!info || !info->containsActivity)
  3006. return;
  3007. if (!info->isActivity)
  3008. {
  3009. unsigned first = getFirstActivityArgument(expr);
  3010. unsigned last = first + getNumActivityArguments(expr);
  3011. for (unsigned idx = first; idx < last; idx++)
  3012. insertResourceSpillPoints(expr->queryChild(idx), expr, ownerOriginalGraph, ownerNewGraph);
  3013. return;
  3014. }
  3015. ResourceGraphInfo * originalGraph = info->graph; //NB: Graph will never cease to exist, so don't need to link.
  3016. if (originalGraph != ownerOriginalGraph)
  3017. return;
  3018. if (info->isSpillPoint)
  3019. createResourceSplit(expr, owner, ownerNewGraph, originalGraph);
  3020. else if (info->graph != ownerNewGraph)
  3021. changeGraph(expr, ownerNewGraph);
  3022. CResources exprResources(clusterSize);
  3023. getResources(expr, exprResources);
  3024. bool ok = info->graph->allocateResources(exprResources, *resourceLimit);
  3025. assertex(ok);
  3026. node_operator op = expr->getOperator();
  3027. if ((op == no_if) || (op == no_choose) || (op == no_chooseds))
  3028. {
  3029. CResources savedResources(info->graph->resources);
  3030. insertResourceSpillPoints(expr->queryChild(1), expr, originalGraph, info->graph);
  3031. ForEachChildFrom(i, expr, 2)
  3032. {
  3033. if (expr->queryChild(i)->isAttribute())
  3034. continue;
  3035. CResources branchResources(info->graph->resources);
  3036. info->graph->resources.set(savedResources);
  3037. insertResourceSpillPoints(expr->queryChild(i), expr, originalGraph, info->graph);
  3038. info->graph->resources.maximize(branchResources);
  3039. }
  3040. }
  3041. else
  3042. {
  3043. unsigned first = getFirstActivityArgument(expr);
  3044. unsigned last = first + getNumActivityArguments(expr);
  3045. for (unsigned idx = first; idx < last; idx++)
  3046. insertResourceSpillPoints(expr->queryChild(idx), expr, originalGraph, info->graph);
  3047. }
  3048. }
  3049. void EclResourcer::resourceSubGraph(ResourceGraphInfo * graph)
  3050. {
  3051. if (graph->beenResourced)
  3052. return;
  3053. graph->beenResourced = true;
  3054. ForEachItemIn(idx, graph->sources)
  3055. resourceSubGraph(graph->sources.item(idx).sourceGraph);
  3056. IHqlExpression * sourceNode = graph->sinks.item(0).sourceNode->queryBody();
  3057. #ifdef _DEBUG
  3058. //Sanity check, ensure there is only a single sink for this graph.
  3059. //However because libraryselects are tightly bound to their library instance there may be multiple library selects.
  3060. //They won't affect the resourcing though, since they'll plug into the same library instance, and the selects use no resources.
  3061. ForEachItemIn(idx2, graph->sinks)
  3062. {
  3063. IHqlExpression * thisSink = graph->sinks.item(idx2).sourceNode->queryBody();
  3064. if (thisSink->getOperator() != no_libraryselect)
  3065. assertex(thisSink == sourceNode);
  3066. }
  3067. #endif
  3068. spilled = false;
  3069. CResources resources(clusterSize);
  3070. calculateResourceSpillPoints(sourceNode, graph, resources, false, false);
  3071. if (spilled)
  3072. insertResourceSpillPoints(sourceNode, NULL, graph, graph);
  3073. else
  3074. graph->resources.set(resources);
  3075. }
  3076. void EclResourcer::resourceSubGraphs(HqlExprArray & exprs)
  3077. {
  3078. ForEachItemIn(idx, graphs)
  3079. resourceSubGraph(&graphs.item(idx));
  3080. }
  3081. //------------------------------------------------------------------------------------------
  3082. // PASS5: Link subrgaphs with dependency information so they don't get merged by accident.
  3083. void EclResourcer::addDependencySource(IHqlExpression * search, ResourceGraphInfo * curGraph, IHqlExpression * expr)
  3084. {
  3085. //MORE: Should we check this doesn't already exist?
  3086. dependencySource.search.append(*LINK(search));
  3087. dependencySource.graphs.append(*LINK(curGraph));
  3088. dependencySource.exprs.append(*LINK(expr));
  3089. }
  3090. void EclResourcer::addDependencyUse(IHqlExpression * search, ResourceGraphInfo * curGraph, IHqlExpression * expr)
  3091. {
  3092. unsigned index = dependencySource.search.find(*search);
  3093. if (index != NotFound)
  3094. {
  3095. if (&dependencySource.graphs.item(index) == curGraph)
  3096. {
  3097. //Don't give a warning if get/set is within the same activity (e.g., within a local())
  3098. if (&dependencySource.exprs.item(index) != expr)
  3099. //errors->reportWarning(HQLWRN_RecursiveDependendencies, HQLWRN_RecursiveDependendencies_Text, *codeGeneratorAtom, 0, 0, 0);
  3100. errors->reportError(HQLWRN_RecursiveDependendencies, HQLWRN_RecursiveDependendencies_Text, codeGeneratorId->str(), 0, 0, 0);
  3101. }
  3102. else
  3103. {
  3104. ResourceGraphLink * link = new ResourceGraphDependencyLink(&dependencySource.graphs.item(index), &dependencySource.exprs.item(index), curGraph, expr);
  3105. curGraph->dependsOn.append(*link);
  3106. links.append(*link);
  3107. }
  3108. }
  3109. }
  3110. void EclResourcer::addRefExprDependency(IHqlExpression * expr, ResourceGraphInfo * curGraph, IHqlExpression * activityExpr)
  3111. {
  3112. IHqlExpression * filename = queryTableFilename(expr);
  3113. if (filename)
  3114. {
  3115. OwnedHqlExpr value = createAttribute(fileAtom, getNormalizedFilename(filename));
  3116. addDependencySource(value, curGraph, activityExpr);
  3117. }
  3118. }
  3119. bool EclResourcer::addExprDependency(IHqlExpression * expr, ResourceGraphInfo * curGraph, IHqlExpression * activityExpr)
  3120. {
  3121. switch (expr->getOperator())
  3122. {
  3123. case no_buildindex:
  3124. case no_output:
  3125. {
  3126. IHqlExpression * filename = queryRealChild(expr, 1);
  3127. if (filename)
  3128. {
  3129. switch (filename->getOperator())
  3130. {
  3131. case no_pipe:
  3132. // allWritten = true;
  3133. break;
  3134. default:
  3135. OwnedHqlExpr value = createAttribute(fileAtom, getNormalizedFilename(filename));
  3136. addDependencySource(value, curGraph, activityExpr);
  3137. break;
  3138. }
  3139. }
  3140. else
  3141. {
  3142. IHqlExpression * seq = querySequence(expr);
  3143. assertex(seq && seq->queryValue());
  3144. IHqlExpression * name = queryResultName(expr);
  3145. OwnedHqlExpr value = createAttribute(resultAtom, LINK(seq), LINK(name));
  3146. addDependencySource(value, curGraph, activityExpr);
  3147. }
  3148. return true;
  3149. }
  3150. case no_keydiff:
  3151. {
  3152. addRefExprDependency(expr->queryChild(0), curGraph, activityExpr);
  3153. addRefExprDependency(expr->queryChild(1), curGraph, activityExpr);
  3154. OwnedHqlExpr value = createAttribute(fileAtom, getNormalizedFilename(expr->queryChild(2)));
  3155. addDependencySource(value, curGraph, activityExpr);
  3156. return true;
  3157. }
  3158. case no_keypatch:
  3159. {
  3160. addRefExprDependency(expr->queryChild(0), curGraph, activityExpr);
  3161. OwnedHqlExpr patchName = createAttribute(fileAtom, getNormalizedFilename(expr->queryChild(1)));
  3162. addDependencyUse(patchName, curGraph, activityExpr);
  3163. OwnedHqlExpr value = createAttribute(fileAtom, getNormalizedFilename(expr->queryChild(2)));
  3164. addDependencySource(value, curGraph, activityExpr);
  3165. return true;
  3166. }
  3167. case no_table:
  3168. {
  3169. IHqlExpression * filename = expr->queryChild(0);
  3170. OwnedHqlExpr value = createAttribute(fileAtom, getNormalizedFilename(filename));
  3171. addDependencyUse(value, curGraph, activityExpr);
  3172. return !filename->isConstant();
  3173. }
  3174. case no_select:
  3175. return isNewSelector(expr);
  3176. case no_workunit_dataset:
  3177. {
  3178. IHqlExpression * sequence = queryAttributeChild(expr, sequenceAtom, 0);
  3179. IHqlExpression * name = queryAttributeChild(expr, nameAtom, 0);
  3180. OwnedHqlExpr value = createAttribute(resultAtom, LINK(sequence), LINK(name));
  3181. addDependencyUse(value, curGraph, activityExpr);
  3182. return false;
  3183. }
  3184. case no_getresult:
  3185. {
  3186. IHqlExpression * sequence = queryAttributeChild(expr, sequenceAtom, 0);
  3187. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  3188. OwnedHqlExpr value = createAttribute(resultAtom, LINK(sequence), LINK(name));
  3189. addDependencyUse(value, curGraph, activityExpr);
  3190. return false;
  3191. }
  3192. case no_getgraphresult:
  3193. {
  3194. OwnedHqlExpr value = createAttribute(resultAtom, LINK(expr->queryChild(1)), LINK(expr->queryChild(2)));
  3195. addDependencyUse(value, curGraph, activityExpr);
  3196. return false;
  3197. }
  3198. case no_setgraphresult:
  3199. {
  3200. OwnedHqlExpr value = createAttribute(resultAtom, LINK(expr->queryChild(1)), LINK(expr->queryChild(2)));
  3201. addDependencySource(value, curGraph, activityExpr);
  3202. return true;
  3203. }
  3204. case no_ensureresult:
  3205. case no_setresult:
  3206. case no_extractresult:
  3207. {
  3208. IHqlExpression * sequence = queryAttributeChild(expr, sequenceAtom, 0);
  3209. IHqlExpression * name = queryAttributeChild(expr, namedAtom, 0);
  3210. OwnedHqlExpr value = createAttribute(resultAtom, LINK(sequence), LINK(name));
  3211. addDependencySource(value, curGraph, activityExpr);
  3212. return true;
  3213. }
  3214. case no_attr:
  3215. case no_attr_link:
  3216. case no_record:
  3217. case no_field:
  3218. return false; //no need to look any further
  3219. default:
  3220. return true;
  3221. }
  3222. }
  3223. void EclResourcer::doAddChildDependencies(IHqlExpression * expr, ResourceGraphInfo * graph, IHqlExpression * activityExpr)
  3224. {
  3225. if (expr->queryTransformExtra())
  3226. return;
  3227. expr->setTransformExtraUnlinked(expr);
  3228. if (addExprDependency(expr, graph, activityExpr))
  3229. {
  3230. ForEachChild(idx, expr)
  3231. doAddChildDependencies(expr->queryChild(idx), graph, activityExpr);
  3232. }
  3233. }
  3234. void EclResourcer::addChildDependencies(IHqlExpression * expr, ResourceGraphInfo * graph, IHqlExpression * activityExpr)
  3235. {
  3236. if (graph)
  3237. {
  3238. lockTransformMutex();
  3239. doAddChildDependencies(expr, graph, activityExpr);
  3240. unlockTransformMutex();
  3241. }
  3242. }
  3243. void EclResourcer::addDependencies(IHqlExpression * expr, ResourceGraphInfo * graph, IHqlExpression * activityExpr)
  3244. {
  3245. ResourcerInfo * info = queryResourceInfo(expr);
  3246. if (info && info->containsActivity)
  3247. {
  3248. if (info->isActivity)
  3249. {
  3250. if (info->gatheredDependencies)
  3251. return;
  3252. info->gatheredDependencies = true;
  3253. graph = info->graph;
  3254. activityExpr = expr;
  3255. }
  3256. if (addExprDependency(expr, graph, activityExpr))
  3257. {
  3258. unsigned first = getFirstActivityArgument(expr);
  3259. unsigned last = first + getNumActivityArguments(expr);
  3260. ForEachChild(idx, expr)
  3261. {
  3262. if ((idx >= first) && (idx < last))
  3263. addDependencies(expr->queryChild(idx), graph, activityExpr);
  3264. else
  3265. addChildDependencies(expr->queryChild(idx), graph, activityExpr);
  3266. }
  3267. }
  3268. }
  3269. else
  3270. addChildDependencies(expr, graph, activityExpr);
  3271. ForEachItemIn(i, info->childDependents)
  3272. {
  3273. IHqlExpression & cur = info->childDependents.item(i);
  3274. if (isResourcedActivity(&cur))
  3275. {
  3276. addDependencies(&cur, NULL, NULL);
  3277. ResourcerInfo * sourceInfo = queryResourceInfo(&cur);
  3278. if (info->childSingleNode.item(i))
  3279. sourceInfo->noteUsedFromChild();
  3280. ResourceGraphLink * link = new ResourceGraphDependencyLink(sourceInfo->graph, &cur, graph, expr);
  3281. graph->dependsOn.append(*link);
  3282. links.append(*link);
  3283. }
  3284. }
  3285. }
  3286. void EclResourcer::addDependencies(HqlExprArray & exprs)
  3287. {
  3288. ForEachItemIn(idx, exprs)
  3289. addDependencies(&exprs.item(idx), NULL, NULL);
  3290. }
  3291. void EclResourcer::spotUnbalancedSplitters(IHqlExpression * expr, unsigned whichSource, IHqlExpression * path, ResourceGraphInfo * graph)
  3292. {
  3293. ResourcerInfo * info = queryResourceInfo(expr);
  3294. if (!info)
  3295. return;
  3296. if (graph && info->graph && info->graph != graph)
  3297. {
  3298. if ((info->currentSource == whichSource) && (info->pathToSplitter != path))
  3299. graph->unbalancedExternalSources.append(*LINK(expr->queryBody()));
  3300. info->currentSource = whichSource;
  3301. info->pathToSplitter.set(path);
  3302. return;
  3303. }
  3304. else
  3305. {
  3306. if (info->currentSource == whichSource)
  3307. {
  3308. if (info->pathToSplitter != path)
  3309. info->balanced = false;
  3310. return;
  3311. }
  3312. info->currentSource = whichSource;
  3313. info->pathToSplitter.set(path);
  3314. }
  3315. if (info->containsActivity)
  3316. {
  3317. unsigned first = getFirstActivityArgument(expr);
  3318. unsigned num = getNumActivityArguments(expr);
  3319. bool modify = false;
  3320. if (num > 1)
  3321. {
  3322. switch (expr->getOperator())
  3323. {
  3324. case no_addfiles:
  3325. if (expr->hasAttribute(_ordered_Atom) || expr->hasAttribute(_orderedPull_Atom) || isGrouped(expr))
  3326. modify = true;
  3327. break;
  3328. default:
  3329. modify = true;
  3330. break;
  3331. }
  3332. }
  3333. unsigned last = first + num;
  3334. for (unsigned idx = first; idx < last; idx++)
  3335. {
  3336. OwnedHqlExpr childPath = modify ? createAttribute(pathAtom, getSizetConstant(idx), LINK(path)) : LINK(path);
  3337. spotUnbalancedSplitters(expr->queryChild(idx), whichSource, childPath, graph);
  3338. }
  3339. }
  3340. //Now check dependencies between graphs (for roxie)
  3341. if (!graph)
  3342. {
  3343. if (info->graph)
  3344. {
  3345. GraphLinkArray & graphLinks = info->graph->dependsOn;
  3346. ForEachItemIn(i, graphLinks)
  3347. {
  3348. ResourceGraphLink & link = graphLinks.item(i);
  3349. if (link.sinkNode == expr)
  3350. {
  3351. OwnedHqlExpr childPath = createAttribute(dependencyAtom, LINK(link.sourceNode), LINK(path));
  3352. spotUnbalancedSplitters(link.sourceNode, whichSource, childPath, graph);
  3353. }
  3354. }
  3355. }
  3356. else
  3357. {
  3358. ForEachItemIn(i, links)
  3359. {
  3360. ResourceGraphLink & link = links.item(i);
  3361. if (link.sinkNode == expr)
  3362. {
  3363. OwnedHqlExpr childPath = createAttribute(dependencyAtom, LINK(link.sourceNode), LINK(path));
  3364. spotUnbalancedSplitters(link.sourceNode, whichSource, childPath, graph);
  3365. }
  3366. }
  3367. }
  3368. }
  3369. }
  3370. void EclResourcer::spotUnbalancedSplitters(HqlExprArray & exprs)
  3371. {
  3372. unsigned curSource = 1;
  3373. switch (targetClusterType)
  3374. {
  3375. case HThorCluster:
  3376. break;
  3377. case ThorLCRCluster:
  3378. {
  3379. //Thor only handles one graph at a time, so only walk expressions within a single graph.
  3380. ForEachItemIn(i1, graphs)
  3381. {
  3382. ResourceGraphInfo & curGraph = graphs.item(i1);
  3383. ForEachItemIn(i2, curGraph.sinks)
  3384. {
  3385. ResourceGraphLink & cur = curGraph.sinks.item(i2);
  3386. spotUnbalancedSplitters(cur.sourceNode, curSource++, 0, &curGraph);
  3387. }
  3388. }
  3389. }
  3390. break;
  3391. case RoxieCluster:
  3392. {
  3393. //Roxie pulls all at once, so need to analyse globally.
  3394. ForEachItemIn(idx, exprs)
  3395. spotUnbalancedSplitters(&exprs.item(idx), curSource++, 0, NULL);
  3396. break;
  3397. }
  3398. }
  3399. }
  3400. void EclResourcer::spotSharedInputs(IHqlExpression * expr, ResourceGraphInfo * graph)
  3401. {
  3402. ResourcerInfo * info = queryResourceInfo(expr);
  3403. if (!info)
  3404. return;
  3405. if (info->graph && info->graph != graph)
  3406. {
  3407. IHqlExpression * body = expr->queryBody();
  3408. if (!graph->unbalancedExternalSources.contains(*body))
  3409. graph->balancedExternalSources.append(*LINK(body));
  3410. return;
  3411. }
  3412. if (info->isSplit())
  3413. {
  3414. //overload currentSource to track if we have visited this splitter before. It cannot have value value NotFound up to now
  3415. if (info->currentSource == NotFound)
  3416. return;
  3417. info->currentSource = NotFound;
  3418. }
  3419. if (info->containsActivity)
  3420. {
  3421. unsigned first = getFirstActivityArgument(expr);
  3422. unsigned num = getNumActivityArguments(expr);
  3423. unsigned last = first + num;
  3424. for (unsigned idx = first; idx < last; idx++)
  3425. {
  3426. spotSharedInputs(expr->queryChild(idx), graph);
  3427. }
  3428. }
  3429. }
  3430. void EclResourcer::spotSharedInputs()
  3431. {
  3432. //Thor only handles one graph at a time, so only walk expressions within a single graph.
  3433. ForEachItemIn(i1, graphs)
  3434. {
  3435. ResourceGraphInfo & curGraph = graphs.item(i1);
  3436. HqlExprCopyArray visited;
  3437. ForEachItemIn(i2, curGraph.sinks)
  3438. {
  3439. ResourceGraphLink & cur = curGraph.sinks.item(i2);
  3440. IHqlExpression * curExpr = cur.sourceNode->queryBody();
  3441. if (!visited.contains(*curExpr))
  3442. {
  3443. ResourcerInfo * info = queryResourceInfo(curExpr);
  3444. if (!info->isExternalSpill() && !info->expandRatherThanSpill(true))
  3445. {
  3446. spotSharedInputs(curExpr, &curGraph);
  3447. visited.append(*curExpr);
  3448. }
  3449. }
  3450. }
  3451. }
  3452. }
  3453. //------------------------------------------------------------------------------------------
  3454. // PASS6: Merge sub graphs that can share resources and don't have dependencies
  3455. // MORE: Once sources are merged, should try merging between trees.
  3456. static bool conditionsMatch(const HqlExprArray & left, const HqlExprArray & right)
  3457. {
  3458. if (left.ordinality() != right.ordinality())
  3459. return false;
  3460. ForEachItemIn(i, left)
  3461. {
  3462. if (!left.contains(right.item(i)) || !right.contains(left.item(i)))
  3463. return false;
  3464. }
  3465. return true;
  3466. }
  3467. bool EclResourcer::queryMergeGraphLink(ResourceGraphLink & link)
  3468. {
  3469. if (link.linkKind == UnconditionalLink)
  3470. {
  3471. //Don't combine any dependencies
  3472. const GraphLinkArray & sinks = link.sourceGraph->sinks;
  3473. ForEachItemIn(i1, sinks)
  3474. {
  3475. ResourceGraphLink & cur = sinks.item(i1);
  3476. if (cur.sinkGraph && cur.sourceNode->isAction())
  3477. return false;
  3478. }
  3479. //Roxie pulls all subgraphs at same time, so no problem with conditional links since handled at run time.
  3480. if (options.noConditionalLinks)
  3481. return true;
  3482. //No conditionals in the sink graph=>will be executed just as frequently
  3483. if (!link.sinkGraph->mergedConditionSource)
  3484. return true;
  3485. //Is this the only place this source graph is used? If so, always fine to merge
  3486. if (sinks.ordinality() == 1)
  3487. return true;
  3488. //1) if context the source graph is being merged into is unconditional, then it is ok [ could have conditional and unconditional paths to same graph]
  3489. //2) if context is conditional, then we don't really want to do it unless the conditions on all sinks are identical, and the only links occur between these two graphs.
  3490. // (situation occurs with spill fed into two branches of a join).
  3491. bool isConditionalInSinkGraph = false;
  3492. bool accessedFromManyGraphs = false;
  3493. ForEachItemIn(i, sinks)
  3494. {
  3495. ResourceGraphLink & cur = sinks.item(i);
  3496. if (cur.sinkNode)
  3497. {
  3498. if (cur.sinkGraph != link.sinkGraph)
  3499. accessedFromManyGraphs = true;
  3500. else
  3501. {
  3502. if (!isConditionalInSinkGraph)
  3503. {
  3504. ResourcerInfo * sinkInfo = queryResourceInfo(cur.sinkNode);
  3505. //If this is conditional, don't merge if there is a link to another graph
  3506. if ((!cur.isDependency() && sinkInfo->isConditionExpr()) ||
  3507. //if (sinkInfo->isConditionExpr() ||
  3508. (!sinkInfo->isUnconditional() && sinkInfo->conditions.ordinality()))
  3509. isConditionalInSinkGraph = true;
  3510. }
  3511. }
  3512. }
  3513. }
  3514. if (isConditionalInSinkGraph && accessedFromManyGraphs)
  3515. return false;
  3516. return true;
  3517. }
  3518. return false;
  3519. }
  3520. unsigned EclResourcer::getMaxDepth() const
  3521. {
  3522. unsigned maxDepth = 0;
  3523. for (unsigned idx = 0; idx < graphs.ordinality(); idx++)
  3524. {
  3525. unsigned depth = graphs.item(idx).getDepth();
  3526. if (depth > maxDepth)
  3527. maxDepth = depth;
  3528. }
  3529. return maxDepth;
  3530. }
  3531. void EclResourcer::mergeSubGraphs(unsigned pass)
  3532. {
  3533. unsigned maxDepth = getMaxDepth();
  3534. for (unsigned curDepth = maxDepth+1; curDepth-- != 0;)
  3535. {
  3536. mergeAgain:
  3537. for (unsigned idx = 0; idx < graphs.ordinality(); idx++)
  3538. {
  3539. ResourceGraphInfo & cur = graphs.item(idx);
  3540. if ((cur.getDepth() == curDepth) && !cur.isDead)
  3541. {
  3542. bool tryAgain;
  3543. do
  3544. {
  3545. tryAgain = false;
  3546. for (unsigned idxSource = 0; idxSource < cur.sources.ordinality(); /*incremented in loop*/)
  3547. {
  3548. ResourceGraphLink & curLink = cur.sources.item(idxSource);
  3549. ResourceGraphInfo * source = curLink.sourceGraph;
  3550. IHqlExpression * sourceNode = curLink.sourceNode;
  3551. bool tryToMerge;
  3552. bool expandSourceInPlace = queryResourceInfo(sourceNode)->expandRatherThanSpill(false);
  3553. if (pass == 0)
  3554. tryToMerge = !expandSourceInPlace;
  3555. else
  3556. tryToMerge = expandSourceInPlace;
  3557. if (tryToMerge)
  3558. {
  3559. bool ok = true;
  3560. ResourcerInfo * sourceResourceInfo = queryResourceInfo(sourceNode);
  3561. if (sourceResourceInfo->outputToUseForSpill && (targetClusterType == HThorCluster))
  3562. {
  3563. if (curLink.sinkNode != sourceResourceInfo->outputToUseForSpill)
  3564. ok = false;
  3565. }
  3566. unsigned curSourceDepth = source->getDepth();
  3567. //MORE: Merging identical conditionals?
  3568. if (ok && queryMergeGraphLink(curLink) &&
  3569. !sourceResourceInfo->expandRatherThanSplit() &&
  3570. cur.mergeInSource(*source, *resourceLimit, (curLink.linkKind == ConditionalLink)))
  3571. {
  3572. //NB: Following cannot remove sources below the current index.
  3573. replaceGraphReferences(source, &cur);
  3574. source->isDead = true;
  3575. #ifdef VERIFY_RESOURCING
  3576. checkRecursion(&cur);
  3577. #endif
  3578. unsigned newDepth = cur.getDepth();
  3579. //Unusual: The source we are merging with has just increased in depth, so any
  3580. //dependents have also increased in depth. Need to try again at different depth
  3581. //to see if one of those will merge in.
  3582. if (newDepth > curSourceDepth)
  3583. {
  3584. curDepth += (newDepth - curSourceDepth);
  3585. goto mergeAgain;
  3586. }
  3587. //depth of this element has changed, so don't check to see if it merges with any other
  3588. //sources on this iteration.
  3589. if (newDepth != curDepth)
  3590. {
  3591. tryAgain = false;
  3592. break;
  3593. }
  3594. tryAgain = true;
  3595. }
  3596. else
  3597. idxSource++;
  3598. }
  3599. else
  3600. idxSource++;
  3601. }
  3602. } while (tryAgain);
  3603. }
  3604. }
  3605. }
  3606. }
  3607. void EclResourcer::mergeSiblings()
  3608. {
  3609. unsigned maxDepth = getMaxDepth();
  3610. for (unsigned curDepth = maxDepth+1; curDepth-- != 0;)
  3611. {
  3612. for (unsigned idx = 0; idx < graphs.ordinality(); idx++)
  3613. {
  3614. ResourceGraphInfo & cur = graphs.item(idx);
  3615. if ((cur.getDepth() == curDepth) && !cur.isDead)
  3616. {
  3617. ForEachItemIn(idxSource, cur.sources)
  3618. {
  3619. ResourceGraphLink & curLink = cur.sources.item(idxSource);
  3620. ResourceGraphInfo * source = curLink.sourceGraph;
  3621. IHqlExpression * sourceNode = curLink.sourceNode;
  3622. ResourcerInfo * sourceInfo = queryResourceInfo(sourceNode);
  3623. if (sourceInfo->neverSplit || sourceInfo->expandRatherThanSplit())
  3624. continue;
  3625. for (unsigned iSink = 0; iSink < source->sinks.ordinality(); )
  3626. {
  3627. ResourceGraphLink & secondLink = source->sinks.item(iSink);
  3628. ResourceGraphInfo * sink = secondLink.sinkGraph;
  3629. if (sink && (sink != &cur) && !sink->isDead && sourceNode->queryBody() == secondLink.sourceNode->queryBody())
  3630. {
  3631. if (cur.mergeInSibling(*sink, *resourceLimit))
  3632. {
  3633. //NB: Following cannot remove sources below the current index.
  3634. replaceGraphReferences(sink, &cur);
  3635. sink->isDead = true;
  3636. }
  3637. else
  3638. iSink++;
  3639. }
  3640. else
  3641. iSink++;
  3642. }
  3643. }
  3644. }
  3645. }
  3646. }
  3647. }
  3648. void EclResourcer::mergeSubGraphs()
  3649. {
  3650. for (unsigned pass=0; pass < 2; pass++)
  3651. mergeSubGraphs(pass);
  3652. if (options.combineSiblings)
  3653. mergeSiblings();
  3654. ForEachItemInRev(idx2, graphs)
  3655. {
  3656. if (graphs.item(idx2).isDead)
  3657. graphs.remove(idx2);
  3658. }
  3659. }
  3660. //------------------------------------------------------------------------------------------
  3661. // PASS7: Optimize aggregates off of splitters into through aggregates.
  3662. bool EclResourcer::optimizeAggregate(IHqlExpression * expr)
  3663. {
  3664. if (!isSimpleAggregateResult(expr))
  3665. return false;
  3666. //expr is a no_extractresult
  3667. if (queryResourceInfo(expr)->childDependents.ordinality())
  3668. return false;
  3669. IHqlExpression * row2ds = expr->queryChild(0); // no_datasetfromrow
  3670. IHqlExpression * selectNth = row2ds->queryChild(0);
  3671. ResourcerInfo * row2dsInfo = queryResourceInfo(row2ds);
  3672. //If more than one set result for the same aggregate don't merge the aggregation because
  3673. //it messes up the internal count. Should really fix it and do multiple stores in the
  3674. //through aggregate.
  3675. if (row2dsInfo->numInternalUses() > 1)
  3676. return false;
  3677. //Be careful not to lose any spills...
  3678. if (row2dsInfo->numExternalUses)
  3679. return false;
  3680. ResourcerInfo * selectNthInfo = queryResourceInfo(selectNth);
  3681. if (selectNthInfo->numExternalUses)
  3682. return false;
  3683. IHqlExpression * aggregate = selectNth->queryChild(0); // no_newaggregate
  3684. IHqlExpression * parent = aggregate->queryChild(0);
  3685. ResourcerInfo * info = queryResourceInfo(parent);
  3686. if (info->numInternalUses() <= 1)
  3687. return false;
  3688. //ok, we can go ahead and merge.
  3689. info->aggregates.append(*LINK(expr));
  3690. // info->numExternalUses--;
  3691. // info->numUses--;
  3692. return true;
  3693. }
  3694. void EclResourcer::optimizeAggregates()
  3695. {
  3696. for (unsigned idx = 0; idx < graphs.ordinality(); idx++)
  3697. {
  3698. ResourceGraphInfo & cur = graphs.item(idx);
  3699. for (unsigned idxSink = 0; idxSink < cur.sinks.ordinality(); /*incremented in loop*/)
  3700. {
  3701. ResourceGraphLink & link = cur.sinks.item(idxSink);
  3702. if ((link.sinkGraph == NULL) && optimizeAggregate(link.sourceNode))
  3703. cur.sinks.remove(idxSink);
  3704. else
  3705. idxSink++;
  3706. }
  3707. }
  3708. }
  3709. //------------------------------------------------------------------------------------------
  3710. // PASS8: Improve efficiency by merging the split points slightly
  3711. IHqlExpression * EclResourcer::findPredecessor(IHqlExpression * expr, IHqlExpression * search, IHqlExpression * prev)
  3712. {
  3713. if (expr == search)
  3714. return prev;
  3715. ResourcerInfo * info = queryResourceInfo(expr);
  3716. if (info && info->containsActivity)
  3717. {
  3718. unsigned first = getFirstActivityArgument(expr);
  3719. unsigned last = first + getNumActivityArguments(expr);
  3720. for (unsigned idx=first; idx < last; idx++)
  3721. {
  3722. IHqlExpression * match = findPredecessor(expr->queryChild(idx), search, expr);
  3723. if (match)
  3724. return match;
  3725. }
  3726. }
  3727. return NULL;
  3728. }
  3729. IHqlExpression * EclResourcer::findPredecessor(ResourcerInfo * search)
  3730. {
  3731. ForEachItemIn(idx, links)
  3732. {
  3733. ResourceGraphLink & cur = links.item(idx);
  3734. if (cur.sourceGraph == search->graph)
  3735. {
  3736. IHqlExpression * match = findPredecessor(cur.sourceNode, search->original, NULL);
  3737. if (match)
  3738. return match;
  3739. }
  3740. }
  3741. return NULL;
  3742. }
  3743. void EclResourcer::moveExternalSpillPoints()
  3744. {
  3745. if (options.minimizeSpillSize == 0)
  3746. return;
  3747. //if we have a external spill point where all the external outputs reduce their data significantly
  3748. //either via a project or a filter, then it might be worth including those activities in the main
  3749. //graph and ,if all external children reduce data, then may be best to filter
  3750. ForEachItemIn(idx, links)
  3751. {
  3752. ResourceGraphLink & cur = links.item(idx);
  3753. if ((cur.linkKind == UnconditionalLink) && cur.sinkGraph)
  3754. {
  3755. while (lightweightAndReducesDatasetSize(cur.sinkNode))
  3756. {
  3757. ResourcerInfo * sourceInfo = queryResourceInfo(cur.sourceNode);
  3758. if (!sourceInfo->isExternalSpill() || (sourceInfo->numExternalUses > options.minimizeSpillSize))
  3759. break;
  3760. ResourcerInfo * sinkInfo = queryResourceInfo(cur.sinkNode);
  3761. if (sinkInfo->numInternalUses() != 1)
  3762. break;
  3763. IHqlExpression * sinkPred = findPredecessor(sinkInfo);
  3764. sinkInfo->graph.set(cur.sourceGraph);
  3765. sourceInfo->numExternalUses--;
  3766. sinkInfo->numExternalUses++;
  3767. cur.sourceNode.set(cur.sinkNode);
  3768. cur.sinkNode.set(sinkPred);
  3769. }
  3770. }
  3771. }
  3772. }
  3773. //------------------------------------------------------------------------------------------
  3774. // PASS9: Create a new expression tree representing the information
  3775. static HqlTransformerInfo childDependentReplacerInfo("ChildDependentReplacer");
  3776. class ChildDependentReplacer : public MergingHqlTransformer
  3777. {
  3778. public:
  3779. ChildDependentReplacer(const HqlExprCopyArray & _childDependents, const HqlExprArray & _replacements)
  3780. : MergingHqlTransformer(childDependentReplacerInfo), childDependents(_childDependents), replacements(_replacements)
  3781. {
  3782. }
  3783. protected:
  3784. virtual IHqlExpression * createTransformed(IHqlExpression * expr)
  3785. {
  3786. unsigned match = childDependents.find(*expr);
  3787. if (match != NotFound)
  3788. return LINK(&replacements.item(match));
  3789. return MergingHqlTransformer::createTransformed(expr);
  3790. }
  3791. protected:
  3792. const HqlExprCopyArray & childDependents;
  3793. const HqlExprArray & replacements;
  3794. };
  3795. static IHqlExpression * getScalarReplacement(IHqlExpression * original, IHqlExpression * replacement)
  3796. {
  3797. IHqlExpression * value = original;
  3798. //First skip any wrappers which are there to cause things to be hoisted.
  3799. loop
  3800. {
  3801. node_operator op = value->getOperator();
  3802. if ((op != no_globalscope) && (op != no_thisnode) && (op != no_evalonce))
  3803. break;
  3804. value = value->queryChild(0);
  3805. }
  3806. //Now modify the spilled result depending on how the spilled result was created (see EclHoistLocator::noteScalar() above)
  3807. if (value->getOperator() == no_select)
  3808. {
  3809. IHqlExpression * field = value->queryChild(1);
  3810. bool isNew;
  3811. IHqlExpression * ds = querySelectorDataset(value, isNew);
  3812. if(isNew || ds->isDatarow())
  3813. {
  3814. if (projectSelectorDatasetToField(ds))
  3815. return createNewSelectExpr(LINK(replacement), LINK(field));
  3816. return replaceSelectorDataset(value, replacement);
  3817. }
  3818. }
  3819. else if (value->getOperator() == no_createset)
  3820. {
  3821. IHqlExpression * record = replacement->queryRecord();
  3822. IHqlExpression * field = record->queryChild(0);
  3823. return createValue(no_createset, original->getType(), LINK(replacement), createSelectExpr(LINK(replacement->queryNormalizedSelector()), LINK(field)));
  3824. }
  3825. IHqlExpression * record = replacement->queryRecord();
  3826. return createNewSelectExpr(LINK(replacement), LINK(record->queryChild(0)));
  3827. }
  3828. IHqlExpression * EclResourcer::replaceResourcedReferences(ResourcerInfo * info, IHqlExpression * expr)
  3829. {
  3830. if (!isAffectedByResourcing(expr))
  3831. return LINK(expr);
  3832. LinkedHqlExpr mapped = expr;
  3833. if (info && (info->childDependents.ordinality()))
  3834. {
  3835. HqlExprArray replacements;
  3836. ForEachItemIn(i, info->originalChildDependents)
  3837. {
  3838. IHqlExpression & cur = info->childDependents.item(i);
  3839. LinkedHqlExpr replacement = &cur;
  3840. if (isResourcedActivity(&cur))
  3841. replacement.setown(createResourced(&cur, NULL, false, false));
  3842. IHqlExpression * original = &info->originalChildDependents.item(i);
  3843. if (!original->isDataset() && !original->isDatarow() && !original->isDictionary())
  3844. replacement.setown(getScalarReplacement(original, replacement));
  3845. replacements.append(*replacement.getClear());
  3846. }
  3847. ChildDependentReplacer replacer(info->originalChildDependents, replacements);
  3848. mapped.setown(replacer.transformRoot(mapped));
  3849. }
  3850. return mapped.getClear();
  3851. }
  3852. IHqlExpression * EclResourcer::doCreateResourced(IHqlExpression * expr, ResourceGraphInfo * ownerGraph, bool expandInParent, bool defineSideEffect)
  3853. {
  3854. ResourcerInfo * info = queryResourceInfo(expr);
  3855. node_operator op = expr->getOperator();
  3856. HqlExprArray args;
  3857. bool same = true;
  3858. unsigned first = getFirstActivityArgument(expr);
  3859. unsigned last = first + getNumActivityArguments(expr);
  3860. OwnedHqlExpr transformed;
  3861. switch (op)
  3862. {
  3863. case no_if:
  3864. case no_choose:
  3865. case no_chooseds:
  3866. {
  3867. ForEachChild(idx, expr)
  3868. {
  3869. IHqlExpression * child = expr->queryChild(idx);
  3870. IHqlExpression * resourced;
  3871. if ((idx < first) || (idx >= last))
  3872. resourced = replaceResourcedReferences(info, child);
  3873. else
  3874. resourced = createResourced(child, ownerGraph, expandInParent, false);
  3875. if (child != resourced)
  3876. same = false;
  3877. args.append(*resourced);
  3878. }
  3879. break;
  3880. }
  3881. case no_case:
  3882. case no_map:
  3883. UNIMPLEMENTED;
  3884. case no_keyed:
  3885. return LINK(expr);
  3886. case no_compound:
  3887. transformed.setown(createResourced(expr->queryChild(1), ownerGraph, expandInParent, false));
  3888. break;
  3889. case no_executewhen:
  3890. {
  3891. args.append(*createResourced(expr->queryChild(0), ownerGraph, expandInParent, false));
  3892. args.append(*createResourced(expr->queryChild(1), ownerGraph, expandInParent, false));
  3893. assertex(args.item(1).getOperator() == no_callsideeffect);
  3894. unwindChildren(args, expr, 2);
  3895. same = false;
  3896. break;
  3897. }
  3898. case no_select:
  3899. {
  3900. IHqlExpression * ds = expr->queryChild(0);
  3901. OwnedHqlExpr newDs = createResourced(ds, ownerGraph, expandInParent, false);
  3902. if (ds != newDs)
  3903. {
  3904. args.append(*LINK(newDs));
  3905. unwindChildren(args, expr, 1);
  3906. if (!expr->hasAttribute(newAtom) && isNewSelector(expr) && (newDs->getOperator() != no_select))
  3907. args.append(*LINK(queryNewSelectAttrExpr()));
  3908. same = false;
  3909. }
  3910. break;
  3911. }
  3912. case no_join:
  3913. case no_denormalize:
  3914. case no_denormalizegroup:
  3915. if (false)//if (isKeyedJoin(expr))
  3916. {
  3917. args.append(*createResourced(expr->queryChild(0), ownerGraph, expandInParent, false));
  3918. args.append(*LINK(expr->queryChild(1)));
  3919. unsigned max = expr->numChildren();
  3920. for (unsigned idx=2; idx < max; idx++)
  3921. args.append(*replaceResourcedReferences(info, expr->queryChild(idx)));
  3922. same = false;
  3923. break;
  3924. }
  3925. //fall through...
  3926. default:
  3927. {
  3928. IHqlExpression * activeTable = NULL;
  3929. // Check to see if the activity has a dataset which is in scope for the rest of its arguments.
  3930. // If so we'll need to remap references from the children.
  3931. if (hasActiveTopDataset(expr) && (first != last))
  3932. activeTable = expr->queryChild(0);
  3933. ForEachChild(idx, expr)
  3934. {
  3935. IHqlExpression * child = expr->queryChild(idx);
  3936. IHqlExpression * resourced;
  3937. if ((idx < first) || (idx >= last))
  3938. {
  3939. LinkedHqlExpr mapped = child;
  3940. if (activeTable && isAffectedByResourcing(child))
  3941. {
  3942. IHqlExpression * activeTableTransformed = &args.item(0);
  3943. if (activeTable != activeTableTransformed)
  3944. mapped.setown(scopedReplaceSelector(child, activeTable, activeTableTransformed));
  3945. }
  3946. resourced = replaceResourcedReferences(info, mapped);
  3947. }
  3948. else
  3949. resourced = createResourced(child, ownerGraph, expandInParent, false);
  3950. if (child != resourced)
  3951. same = false;
  3952. args.append(*resourced);
  3953. }
  3954. }
  3955. break;
  3956. }
  3957. if (!transformed)
  3958. transformed.setown(same ? LINK(expr) : expr->clone(args));
  3959. if (!expandInParent)
  3960. {
  3961. if (!transformed->isAction())
  3962. transformed.setown(info->createTransformedExpr(transformed));
  3963. else if (defineSideEffect)
  3964. transformed.setown(createValue(no_definesideeffect, LINK(transformed), createUniqueId()));
  3965. }
  3966. return transformed.getClear();
  3967. }
  3968. /*
  3969. Need to be careful because result should not reuse the same expression tree unless that element is a splitter.
  3970. createResourced()
  3971. {
  3972. if (!isActivity)
  3973. if (!containsActivity)
  3974. replace any refs to the activeTable with whatever it has been mapped to
  3975. else
  3976. recurse
  3977. else if (!isDefinedInSameGraph)
  3978. expand/create reader
  3979. set active table
  3980. else isSplitter and alreadyGeneratedForThisGraph
  3981. return previous result
  3982. else
  3983. create transformed
  3984. }
  3985. */
  3986. void EclResourcer::doCheckRecursion(ResourceGraphInfo * graph, PointerArray & visited)
  3987. {
  3988. visited.append(graph);
  3989. ForEachItemIn(idxD, graph->dependsOn)
  3990. checkRecursion(graph->dependsOn.item(idxD).sourceGraph, visited);
  3991. ForEachItemIn(idxS, graph->sources)
  3992. checkRecursion(graph->sources.item(idxS).sourceGraph, visited);
  3993. visited.pop();
  3994. }
  3995. void EclResourcer::checkRecursion(ResourceGraphInfo * graph, PointerArray & visited)
  3996. {
  3997. if (visited.find(graph) != NotFound)
  3998. throwUnexpected();
  3999. doCheckRecursion(graph, visited);
  4000. }
  4001. void EclResourcer::checkRecursion(ResourceGraphInfo * graph)
  4002. {
  4003. PointerArray visited;
  4004. doCheckRecursion(graph, visited);
  4005. }
  4006. IHqlExpression * EclResourcer::createResourced(IHqlExpression * expr, ResourceGraphInfo * ownerGraph, bool expandInParent, bool defineSideEffect)
  4007. {
  4008. ResourcerInfo * info = queryResourceInfo(expr);
  4009. if (!info || !info->containsActivity)
  4010. return replaceResourcedReferences(info, expr);
  4011. if (!info->isActivity)
  4012. {
  4013. assertex(!defineSideEffect);
  4014. HqlExprArray args;
  4015. bool same = true;
  4016. ForEachChild(idx, expr)
  4017. {
  4018. IHqlExpression * cur = expr->queryChild(idx);
  4019. IHqlExpression * curResourced = createResourced(cur, ownerGraph, expandInParent, false);
  4020. args.append(*curResourced);
  4021. if (cur != curResourced)
  4022. same = false;
  4023. }
  4024. if (same)
  4025. return LINK(expr);
  4026. return expr->clone(args);
  4027. }
  4028. if (info->graph != ownerGraph)
  4029. {
  4030. assertex(!defineSideEffect);
  4031. bool isShared = options.optimizeSharedInputs && ownerGraph && ownerGraph->isSharedInput(expr);
  4032. if (isShared)
  4033. {
  4034. IHqlExpression * mapped = ownerGraph->queryMappedSharedInput(expr->queryBody());
  4035. if (mapped)
  4036. return LINK(mapped);
  4037. }
  4038. IHqlExpression * source;
  4039. if (info->expandRatherThanSpill(true))
  4040. {
  4041. bool expandChildInParent = options.minimiseSpills ? expandInParent : true;
  4042. OwnedHqlExpr resourced = doCreateResourced(expr, ownerGraph, expandChildInParent, false);
  4043. if (queryAddUniqueToActivity(resourced))
  4044. source = appendUniqueAttr(resourced);
  4045. else
  4046. source = LINK(resourced);
  4047. }
  4048. else
  4049. {
  4050. if (!expr->isAction())
  4051. {
  4052. OwnedHqlExpr reason;
  4053. if (ownerGraph && options.checkResources())
  4054. {
  4055. StringBuffer reasonText;
  4056. ownerGraph->getMergeFailReason(reasonText, info->graph, *resourceLimit);
  4057. if (reasonText.length())
  4058. {
  4059. reasonText.insert(0, "Resource limit spill: ");
  4060. reason.setown(createAttribute(_spillReason_Atom, createConstant(reasonText.str())));
  4061. }
  4062. }
  4063. source = info->createSpilledRead(reason);
  4064. }
  4065. else
  4066. {
  4067. IHqlExpression * uid = info->transformed->queryAttribute(_uid_Atom);
  4068. source = createValue(no_callsideeffect, makeVoidType(), LINK(uid));
  4069. //source = LINK(info->transformed);
  4070. }
  4071. }
  4072. if (isShared)
  4073. {
  4074. source = createDatasetF(no_split, source, createAttribute(balancedAtom), createUniqueId(), NULL);
  4075. ownerGraph->addSharedInput(expr->queryBody(), source);
  4076. }
  4077. return source;
  4078. }
  4079. if (!expandInParent && info->transformed && info->isSplit())
  4080. {
  4081. return LINK(info->transformed);
  4082. }
  4083. OwnedHqlExpr resourced = doCreateResourced(expr, ownerGraph, expandInParent, defineSideEffect);
  4084. if (queryAddUniqueToActivity(resourced))// && !resourced->hasAttribute(_internal_Atom))
  4085. resourced.setown(appendUniqueAttr(resourced));
  4086. if (!expandInParent)
  4087. {
  4088. info->transformed = resourced;
  4089. }
  4090. return resourced.getClear();
  4091. }
  4092. void EclResourcer::createResourced(ResourceGraphInfo * graph, HqlExprArray & transformed)
  4093. {
  4094. if (graph->createdGraph || graph->isDead)
  4095. return;
  4096. if (!graph->containsActiveSinks() && (!graph->hasConditionSource))
  4097. return;
  4098. #ifdef VERIFY_RESOURCING
  4099. checkRecursion(graph);
  4100. #endif
  4101. // DBGLOG("Prepare to CreateResourced(%p)", graph);
  4102. if (graph->startedGeneratingResourced)
  4103. throwError(HQLWRN_RecursiveDependendencies);
  4104. graph->startedGeneratingResourced = true;
  4105. ForEachItemIn(idxD, graph->dependsOn)
  4106. createResourced(graph->dependsOn.item(idxD).sourceGraph, transformed);
  4107. ForEachItemIn(idxS, graph->sources)
  4108. createResourced(graph->sources.item(idxS).sourceGraph, transformed);
  4109. // DBGLOG("Create resourced %p", graph);
  4110. //First generate the graphs for all the unconditional sinks
  4111. HqlExprArray args;
  4112. ForEachItemIn(idx, graph->sinks)
  4113. {
  4114. ResourceGraphLink & sink = graph->sinks.item(idx);
  4115. IHqlExpression * sinkNode = sink.sourceNode;
  4116. ResourcerInfo * info = queryResourceInfo(sinkNode);
  4117. //If graph is unconditional, any condition sinks are forced to be generated (and spilt)
  4118. if (!info->transformed)
  4119. {
  4120. // if it is a spiller, then it will be generated from another sink
  4121. if (!info->isExternalSpill())
  4122. {
  4123. IHqlExpression * resourced = createResourced(sinkNode, graph, false, sinkNode->isAction() && sink.sinkGraph);
  4124. assertex(info->transformed);
  4125. args.append(*resourced);
  4126. }
  4127. }
  4128. }
  4129. ForEachItemIn(i2, graph->sinks)
  4130. {
  4131. ResourceGraphLink & sink = graph->sinks.item(i2);
  4132. IHqlExpression * sinkNode = sink.sourceNode;
  4133. ResourcerInfo * info = queryResourceInfo(sinkNode);
  4134. IHqlExpression * splitter = info->splitterOutput;
  4135. if (splitter && !args.contains(*splitter))
  4136. args.append(*LINK(splitter));
  4137. }
  4138. if (args.ordinality() == 0)
  4139. graph->isDead = true;
  4140. else
  4141. {
  4142. if (options.useGraphResults)
  4143. args.append(*createAttribute(childAtom));
  4144. graph->createdGraph.setown(createValue(no_subgraph, makeVoidType(), args));
  4145. transformed.append(*LINK(graph->createdGraph));
  4146. }
  4147. }
  4148. void EclResourcer::inheritRedundantDependencies(ResourceGraphInfo * thisGraph)
  4149. {
  4150. if (thisGraph->inheritedExpandedDependencies)
  4151. return;
  4152. thisGraph->inheritedExpandedDependencies = true;
  4153. ForEachItemIn(idx, thisGraph->sources)
  4154. {
  4155. ResourceGraphLink & cur = thisGraph->sources.item(idx);
  4156. if (cur.isRedundantLink())
  4157. {
  4158. inheritRedundantDependencies(cur.sourceGraph);
  4159. ForEachItemIn(i, cur.sourceGraph->dependsOn)
  4160. {
  4161. ResourceGraphLink & curDepend = cur.sourceGraph->dependsOn.item(i);
  4162. ResourceGraphLink * link = new ResourceGraphDependencyLink(curDepend.sourceGraph, curDepend.sourceNode, thisGraph, cur.sinkNode);
  4163. thisGraph->dependsOn.append(*link);
  4164. links.append(*link);
  4165. }
  4166. }
  4167. }
  4168. }
  4169. void EclResourcer::createResourced(HqlExprArray & transformed)
  4170. {
  4171. //Before removing null links (e.g., where the source graph is expanded inline), need to make sure
  4172. //dependencies are cloned, otherwise graphs can be generated in the wrong order
  4173. ForEachItemIn(idx1, graphs)
  4174. inheritRedundantDependencies(&graphs.item(idx1));
  4175. ForEachItemInRev(idx2, links)
  4176. {
  4177. ResourceGraphLink & cur = links.item(idx2);
  4178. if (cur.isRedundantLink())
  4179. removeLink(cur, true);
  4180. }
  4181. ForEachItemIn(idx3, graphs)
  4182. createResourced(&graphs.item(idx3), transformed);
  4183. }
  4184. static int compareGraphDepth(CInterface * * _l, CInterface * * _r)
  4185. {
  4186. ResourceGraphInfo * l = (ResourceGraphInfo *)*_l;
  4187. ResourceGraphInfo * r = (ResourceGraphInfo *)*_r;
  4188. return l->getDepth() - r->getDepth();
  4189. }
  4190. static int compareLinkDepth(CInterface * * _l, CInterface * * _r)
  4191. {
  4192. ResourceGraphLink * l = (ResourceGraphLink *)*_l;
  4193. ResourceGraphLink * r = (ResourceGraphLink *)*_r;
  4194. int diff = l->sourceGraph->getDepth() - r->sourceGraph->getDepth();
  4195. if (diff) return diff;
  4196. if (l->sinkGraph)
  4197. if (r->sinkGraph)
  4198. return l->sinkGraph->getDepth() - r->sinkGraph->getDepth();
  4199. else
  4200. return -1;
  4201. else
  4202. if (r->sinkGraph)
  4203. return +1;
  4204. else
  4205. return 0;
  4206. }
  4207. void EclResourcer::display(StringBuffer & out)
  4208. {
  4209. CIArrayOf<ResourceGraphInfo> sortedGraphs;
  4210. ForEachItemIn(j1, graphs)
  4211. sortedGraphs.append(OLINK(graphs.item(j1)));
  4212. sortedGraphs.sort(compareGraphDepth);
  4213. out.append("Graphs:\n");
  4214. ForEachItemIn(i, sortedGraphs)
  4215. {
  4216. ResourceGraphInfo & cur = sortedGraphs.item(i);
  4217. out.appendf("%d: depth(%d) uncond(%d) cond(%d) %s {%p}\n", i, cur.getDepth(), cur.isUnconditional, cur.hasConditionSource, cur.isDead ? "dead" : "", &cur);
  4218. ForEachItemIn(j, cur.sources)
  4219. {
  4220. ResourceGraphLink & link = cur.sources.item(j);
  4221. out.appendf(" Source: %p %s\n", link.sinkNode.get(), getOpString(link.sinkNode->getOperator()));
  4222. }
  4223. ForEachItemIn(k, cur.sinks)
  4224. {
  4225. ResourceGraphLink & link = cur.sinks.item(k);
  4226. IHqlExpression * sourceNode = link.sourceNode;
  4227. ResourcerInfo * sourceInfo = queryResourceInfo(sourceNode);
  4228. out.appendf(" Sink: %p %s cond(%d,%d) int(%d) ext(%d)\n", sourceNode, getOpString(sourceNode->getOperator()), sourceInfo->conditions.ordinality(), sourceInfo->conditionSourceCount, sourceInfo->numInternalUses(), sourceInfo->numExternalUses);
  4229. }
  4230. ForEachItemIn(i3, dependencySource.graphs)
  4231. {
  4232. if (&dependencySource.graphs.item(i3) == &cur)
  4233. {
  4234. StringBuffer s;
  4235. toECL(&dependencySource.search.item(i3), s);
  4236. out.appendf(" Creates: %s\n", s.str());
  4237. }
  4238. }
  4239. }
  4240. out.append("Links:\n");
  4241. CIArrayOf<ResourceGraphLink> sortedLinks;
  4242. ForEachItemIn(j2, links)
  4243. sortedLinks.append(OLINK(links.item(j2)));
  4244. sortedLinks.sort(compareLinkDepth);
  4245. ForEachItemIn(i2, sortedLinks)
  4246. {
  4247. ResourceGraphLink & link = sortedLinks.item(i2);
  4248. unsigned len = out.length();
  4249. out.appendf(" Source: %d %s", sortedGraphs.find(*link.sourceGraph), getOpString(link.sourceNode->getOperator()));
  4250. if (link.sinkNode)
  4251. {
  4252. out.padTo(len+30);
  4253. out.appendf(" Sink: %d %s", sortedGraphs.find(*link.sinkGraph), getOpString(link.sinkNode->getOperator()));
  4254. }
  4255. if (link.linkKind == ConditionalLink)
  4256. out.append(" <conditional>");
  4257. else if (link.linkKind == SequenceLink)
  4258. out.append(" <sequence>");
  4259. out.newline();
  4260. }
  4261. }
  4262. void EclResourcer::trace()
  4263. {
  4264. StringBuffer s;
  4265. display(s);
  4266. DBGLOG("%s", s.str());
  4267. }
  4268. //---------------------------------------------------------------------------
  4269. void EclResourcer::resourceGraph(HqlExprArray & exprs, HqlExprArray & transformed)
  4270. {
  4271. //NB: This only resources a single level of queries. SubQueries should be resourced in a separate
  4272. //pass so that commonality between different activities/subgraphs isn't introduced/messed up.
  4273. findSplitPoints(exprs);
  4274. createInitialGraphs(exprs);
  4275. markConditions(exprs);
  4276. if (options.checkResources())
  4277. resourceSubGraphs(exprs);
  4278. addDependencies(exprs);
  4279. #ifdef TRACE_RESOURCING
  4280. trace();
  4281. #endif
  4282. mergeSubGraphs();
  4283. #ifdef TRACE_RESOURCING
  4284. trace();
  4285. #endif
  4286. spotUnbalancedSplitters(exprs);
  4287. if (options.optimizeSharedInputs)
  4288. spotSharedInputs();
  4289. if (spotThroughAggregate)
  4290. optimizeAggregates();
  4291. moveExternalSpillPoints();
  4292. createResourced(transformed);
  4293. }
  4294. void EclResourcer::resourceRemoteGraph(HqlExprArray & exprs, HqlExprArray & transformed)
  4295. {
  4296. //NB: This only resources a single level of queries. SubQueries should be resourced in a separate
  4297. //pass so that commonality between different activities/subgraphs isn't introduced/messed up.
  4298. findSplitPoints(exprs);
  4299. createInitialRemoteGraphs(exprs);
  4300. markConditions(exprs);
  4301. addDependencies(exprs);
  4302. #ifdef TRACE_RESOURCING
  4303. trace();
  4304. #endif
  4305. mergeSubGraphs();
  4306. #ifdef TRACE_RESOURCING
  4307. trace();
  4308. #endif
  4309. createResourced(transformed);
  4310. }
  4311. //---------------------------------------------------------------------------
  4312. void expandLists(HqlExprArray & args, IHqlExpression * expr)
  4313. {
  4314. switch (expr->getOperator())
  4315. {
  4316. case no_comma:
  4317. case no_compound:
  4318. case no_parallel:
  4319. case no_actionlist:
  4320. // for the moment, expand root parallel nodes, it generates much better code.
  4321. // I should really come up with a better way of implementing sequential/parallel.
  4322. {
  4323. ForEachChild(idx, expr)
  4324. expandLists(args, expr->queryChild(idx));
  4325. break;
  4326. }
  4327. default:
  4328. args.append(*LINK(expr));
  4329. break;
  4330. }
  4331. }
  4332. IHqlExpression * resourceThorGraph(HqlCppTranslator & translator, IHqlExpression * expr, ClusterType targetClusterType, unsigned clusterSize, IHqlExpression * graphIdExpr)
  4333. {
  4334. HqlExprArray transformed;
  4335. {
  4336. EclResourcer resourcer(translator.queryErrors(), translator.wu(), targetClusterType, clusterSize, translator.queryOptions());
  4337. if (graphIdExpr)
  4338. resourcer.setNewChildQuery(graphIdExpr, 0);
  4339. HqlExprArray exprs;
  4340. expandLists(exprs, expr);
  4341. resourcer.resourceGraph(exprs, transformed);
  4342. }
  4343. hoistNestedCompound(translator, transformed);
  4344. return createActionList(transformed);
  4345. }
  4346. static IHqlExpression * doResourceGraph(HqlCppTranslator & translator, HqlExprCopyArray * activeRows, IHqlExpression * expr,
  4347. ClusterType targetClusterType, unsigned clusterSize,
  4348. IHqlExpression * graphIdExpr, unsigned * numResults, bool isChild, bool useGraphResults, bool sequential)
  4349. {
  4350. HqlExprArray transformed;
  4351. {
  4352. EclResourcer resourcer(translator.queryErrors(), translator.wu(), targetClusterType, clusterSize, translator.queryOptions());
  4353. if (isChild)
  4354. resourcer.setChildQuery(true);
  4355. resourcer.setNewChildQuery(graphIdExpr, *numResults);
  4356. resourcer.setUseGraphResults(useGraphResults);
  4357. resourcer.setSequential(sequential);
  4358. if (activeRows)
  4359. resourcer.tagActiveCursors(*activeRows);
  4360. HqlExprArray exprs;
  4361. expandLists(exprs, expr);
  4362. resourcer.resourceGraph(exprs, transformed);
  4363. *numResults = resourcer.numGraphResults();
  4364. }
  4365. hoistNestedCompound(translator, transformed);
  4366. return createActionList(transformed);
  4367. }
  4368. IHqlExpression * resourceLibraryGraph(HqlCppTranslator & translator, IHqlExpression * expr, ClusterType targetClusterType, unsigned clusterSize, IHqlExpression * graphIdExpr, unsigned * numResults)
  4369. {
  4370. return doResourceGraph(translator, NULL, expr, targetClusterType, clusterSize, graphIdExpr, numResults, false, true, false); //?? what value for isChild (e.g., thor library call). Need to gen twice?
  4371. }
  4372. IHqlExpression * resourceNewChildGraph(HqlCppTranslator & translator, HqlExprCopyArray & activeRows, IHqlExpression * expr, ClusterType targetClusterType, IHqlExpression * graphIdExpr, unsigned * numResults, bool sequential)
  4373. {
  4374. return doResourceGraph(translator, &activeRows, expr, targetClusterType, 0, graphIdExpr, numResults, true, true, sequential);
  4375. }
  4376. IHqlExpression * resourceLoopGraph(HqlCppTranslator & translator, HqlExprCopyArray & activeRows, IHqlExpression * expr, ClusterType targetClusterType, IHqlExpression * graphIdExpr, unsigned * numResults, bool insideChildQuery)
  4377. {
  4378. return doResourceGraph(translator, &activeRows, expr, targetClusterType, 0, graphIdExpr, numResults, insideChildQuery, true, false);
  4379. }
  4380. IHqlExpression * resourceRemoteGraph(HqlCppTranslator & translator, IHqlExpression * expr, ClusterType targetClusterType, unsigned clusterSize)
  4381. {
  4382. HqlExprArray transformed;
  4383. {
  4384. EclResourcer resourcer(translator.queryErrors(), translator.wu(), targetClusterType, clusterSize, translator.queryOptions());
  4385. HqlExprArray exprs;
  4386. expandLists(exprs, expr);
  4387. resourcer.resourceRemoteGraph(exprs, transformed);
  4388. }
  4389. hoistNestedCompound(translator, transformed);
  4390. return createActionList(transformed);
  4391. }
  4392. /*
  4393. Conditions:
  4394. They are nasty. We process the tree in two passes. First we tag anything which must be evaluated, and
  4395. save a list of condition statements to process later.
  4396. Second pass we tag conditionals.
  4397. a) all left and right branches of a condition are tagged. [conditionSourceCount]
  4398. b) all conditional expressions are tagged with the conditions they are evaluated for.
  4399. [if the condition lists match then it should be possible to merge the graphs]
  4400. c) The spill count for an node should ignore the number of links from conditional graphs,
  4401. but should add the number of conditions.
  4402. d) if (a, b(f1) +b(f2), c) needs to link b twice though!
  4403. */
  4404. /*
  4405. This transformer converts spill activities to no_dataset/no_output, and also converts splitters of splitters into
  4406. a single splitter.
  4407. */
  4408. class SpillActivityTransformer : public NewHqlTransformer
  4409. {
  4410. public:
  4411. SpillActivityTransformer();
  4412. protected:
  4413. virtual void analyseExpr(IHqlExpression * expr);
  4414. virtual IHqlExpression * createTransformed(IHqlExpression * expr);
  4415. bool isUnbalanced(IHqlExpression * body)
  4416. {
  4417. ANewTransformInfo * info = queryTransformExtra(body);
  4418. return info->spareByte1 != 0;
  4419. }
  4420. void setUnbalanced(IHqlExpression * body)
  4421. {
  4422. ANewTransformInfo * info = queryTransformExtra(body);
  4423. info->spareByte1 = true;
  4424. }
  4425. };
  4426. static HqlTransformerInfo spillActivityTransformerInfo("SpillActivityTransformer");
  4427. SpillActivityTransformer::SpillActivityTransformer()
  4428. : NewHqlTransformer(spillActivityTransformerInfo)
  4429. {
  4430. }
  4431. void SpillActivityTransformer::analyseExpr(IHqlExpression * expr)
  4432. {
  4433. IHqlExpression * body = expr->queryBody();
  4434. if (alreadyVisited(body))
  4435. return;
  4436. if (body->getOperator() == no_split)
  4437. {
  4438. IHqlExpression * input = body->queryChild(0);
  4439. if (input->getOperator() == no_split)
  4440. {
  4441. loop
  4442. {
  4443. IHqlExpression * cur = input->queryChild(0);
  4444. if (cur->getOperator() != no_split)
  4445. break;
  4446. input = cur;
  4447. }
  4448. if (!body->hasAttribute(balancedAtom))
  4449. setUnbalanced(input->queryBody());
  4450. }
  4451. }
  4452. NewHqlTransformer::analyseExpr(expr);
  4453. }
  4454. IHqlExpression * SpillActivityTransformer::createTransformed(IHqlExpression * expr)
  4455. {
  4456. IHqlExpression * annotation = queryTransformAnnotation(expr);
  4457. if (annotation)
  4458. return annotation;
  4459. switch (expr->getOperator())
  4460. {
  4461. case no_split:
  4462. {
  4463. IHqlExpression * input = expr->queryChild(0);
  4464. if (input->getOperator() == no_split)
  4465. return transform(input);
  4466. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  4467. if (transformed->hasAttribute(balancedAtom) && isUnbalanced(expr))
  4468. return removeProperty(transformed, balancedAtom);
  4469. return transformed.getClear();
  4470. }
  4471. case no_writespill:
  4472. {
  4473. HqlExprArray args;
  4474. transformChildren(expr, args);
  4475. return createValue(no_output, makeVoidType(), args);
  4476. }
  4477. case no_commonspill:
  4478. return transform(expr->queryChild(0));
  4479. case no_readspill:
  4480. {
  4481. OwnedHqlExpr ds = transform(expr->queryChild(0));
  4482. HqlExprArray args;
  4483. args.append(*transform(expr->queryChild(1)));
  4484. args.append(*LINK(ds->queryRecord()));
  4485. ForEachChildFrom(i, expr, 2)
  4486. {
  4487. IHqlExpression * cur = expr->queryChild(i);
  4488. args.append(*transform(cur));
  4489. }
  4490. IHqlExpression * recordCountAttr = queryRecordCountInfo(expr);
  4491. if (recordCountAttr)
  4492. args.append(*LINK(recordCountAttr));
  4493. return createDataset(no_table, args);
  4494. }
  4495. }
  4496. return NewHqlTransformer::createTransformed(expr);
  4497. }
  4498. IHqlExpression * convertSpillsToActivities(IHqlExpression * expr)
  4499. {
  4500. SpillActivityTransformer transformer;
  4501. transformer.analyse(expr, 0);
  4502. return transformer.transformRoot(expr);
  4503. }