W1¬Ū{NÅ Ł”K7Schema’’’’’’’’ Path Test’’’’’’’’Performance Modelling Tutorial’’’’’’’’’’’’—č½ל¾>Š7 smtb.Add(BackupSwitchText); rightcol.Shapes append smtb; endlocals; endif; if ShowRoutingGateways then locals rgtb := new InfoTextBox; rghd := new HeadingTextLine call SetUp("Routing, and Gateways"); do üÕ¼ūoś<,ĶĶĶ3 ’’’’ĶĶĶĶ’’’’ĶĶĶĶÅ’ĶĶ’’’’ĶĶĶĶ=$Performance Model  S Ė €G'  Š  ē č é ź ė ģ 2008v2 ę ZFor more information see: www.WeaverBird.org’ĶĶ’’’’ĶĶĶĶRM Base  ’ĶĶ’’’’ĶĶĶĶ?NamedObj€'      ’ĶĶ’’’’ĶĶĶĶD Name ’ĶĶ’’’’ĶĶĶĶ EGetName    ’ĶĶ’’’’ĶĶĶĶ FSetName   ’ĶĶ’’’’ĶĶĶĶ In ’ĶĶ’’’’ĶĶĶĶHHasName  ’ĶĶ’’’’ĶĶĶĶ?System€'    ’ĶĶ’’’’ĶĶĶĶD Title ’ĶĶ’’’’ĶĶĶĶD(ImplementationPaths Ō ’ĶĶ’’’’ĶĶĶĶDITResources × ’ĶĶ’’’’ĶĶĶĶ?&ImplementationPath€'       Ó ’ĶĶ’’’’ĶĶĶĶDNumber  ’ĶĶ’’’’ĶĶĶĶDActions Ū ’ĶĶ’’’’ĶĶĶĶDErrorDetection  ’ĶĶ’’’’ĶĶĶĶDRecoveryAction $ ’ĶĶ’’’’ĶĶĶĶA ErrorDetectEnum€'  ’ĶĶ’’’’ĶĶĶĶ!JeTimeout’ĶĶ’’’’ĶĶĶĶ"J ePoll’ĶĶ’’’’ĶĶĶĶ#JeReport’ĶĶ’’’’ĶĶĶĶ$ARecoveryEnum€' % ’ĶĶ’’’’ĶĶĶĶ&JeReversal’ĶĶ’’’’ĶĶĶĶ'J,eManualReconciliation’ĶĶ’’’’ĶĶĶĶ(JeNotNeeded’ĶĶ’’’’ĶĶĶĶ)?ITResource€' *  +  ,  Ö ’ĶĶ’’’’ĶĶĶĶ.DCategory 4  - ’ĶĶ’’’’ĶĶĶĶ0DNumber / ’ĶĶ’’’’ĶĶĶĶ2D Units 1 ’ĶĶ’’’’ĶĶĶĶ3DUtilizedBy Ł ’ĶĶ’’’’ĶĶĶĶ4AITResourceEnum€' 5 ’ĶĶ’’’’ĶĶĶĶ6JeFixed’ĶĶ’’’’ĶĶĶĶ7JeQueued’ĶĶ’’’’ĶĶĶĶ8JeTimesliced’ĶĶ’’’’ĶĶĶĶ9?UtilResource€' :  ;  Ų ’ĶĶ’’’’ĶĶĶĶ<DResource ) UtilizedBy’ĶĶ’’’’ĶĶĶĶ>DUnitsUtil = ’ĶĶ’’’’ĶĶĶĶ@D BackgroundUnits ? ’ĶĶ’’’’ĶĶĶĶBDUtilByUser A ’ĶĶ’’’’ĶĶĶĶCDImpAction D ’ĶĶ’’’’ĶĶĶĶD?ImpAction€' E  F  G  Ś ’ĶĶ’’’’ĶĶĶĶHD Utils Ł ImpAction’ĶĶ’’’’ĶĶĶĶIDSubActions Ū ’ĶĶ’’’’ĶĶĶĶKD$TransactionNeeded J ’ĶĶ’’’’ĶĶĶĶMHResourceUsage L ’ĶĶ’’’’ĶĶĶĶN?ProcAction€' O ’ĶĶ’’’’ĶĶĶĶP?MsgAction€' Q ’ĶĶ’’’’ĶĶĶͱMCommon T ’ĶĶ’’’’ĶĶĶĶU? MainStripeFrame€' V  ’ĶĶ’’’’ĶĶĶĶW?MainStripeVert€' X  ‘’ĶĶ’’’’ĶĶĶĶY?"HorzStripeSimple€' Z  ’’ĶĶ’’’’ĶĶĶĶ[?BoxWithName€' \  ]  ^ ’ĶĶ’’’’ĶĶĶĶ_DDataObject  ’ĶĶ’’’’ĶĶĶĶcFChangeTitle ~ b ` ’ĶĶ’’’’ĶĶĶĶaINewText ’ĶĶ’’’’ĶĶĶĶd?StripeWithName€' e  f  g ’ĶĶ’’’’ĶĶĶĶhDDataObject  ’ĶĶ’’’’ĶĶĶĶlFChangeTitle ~ k i ’ĶĶ’’’’ĶĶĶĶjINewText ’ĶĶ’’’’ĶĶĶĶm?TitleBox€ ' n  o W p üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüź`°±įbü¤’ĶĶ’’’’ĶĶĶĶqD Names ’ĶĶ’’’’ĶĶĶĶrDNamesCount’ĶĶ’’’’ĶĶĶĶsDMainObj  ’ĶĶ’’’’ĶĶĶĶwF SetUp v t ’ĶĶ’’’’ĶĶĶĶuIpr ’ĶĶ’’’’ĶĶĶĶ{FAdd z x ’ĶĶ’’’’ĶĶĶĶyIn  ’ĶĶ’’’’ĶĶĶĶFChangeTitle ~ ~ | ’ĶĶ’’’’ĶĶĶĶ}INewText ’ĶĶ’’’’ĶĶĶĶ€ABigSmallEnum€!'  ’ĶĶ’’’’ĶĶĶĶ‚J eBig’ĶĶ’’’’ĶĶĶ̓JeSmall’ĶĶ’’’’ĶĶĶĶ„?InfoTextBox€"' …  † Ŗ ‡ ’ĶĶ’’’’ĶĶĶĶ‹FAdd Š ˆ ’ĶĶ’’’’ĶĶĶ͉Iitl Œ ’ĶĶ’’’’ĶĶĶ͌?InfoTextLine€#'   Ž   ’ĶĶ’’’’ĶĶĶĶ‘DMargin  ’ĶĶ’’’’ĶĶĶĶ’? HeadingTextLine€$' “  ” Ķ • ’ĶĶ’’’’ĶĶĶĶ–DMsg ’ĶĶ’’’’ĶĶĶ͚F SetUp ™ — ’ĶĶ’’’’ĶĶĶ͘Imsg ’ĶĶ’’’’ĶĶĶĶ›?BlankTextLine€%' œ  Ī’ĶĶ’’’’ĶĶĶĶ? IntInfoTextLine€&' ž  Ÿ «   ’ĶĶ’’’’ĶĶĶĶ”DVal’ĶĶ’’’’ĶĶĶĶ¢DMsg ’ĶĶ’’’’ĶĶĶͦF SetUp „ £ ’ĶĶ’’’’ĶĶĶͤImsg ’ĶĶ’’’’ĶĶĶͧ?$FloatInfoTextLine€'' Ø  © ® Ŗ ’ĶĶ’’’’ĶĶĶĶ«DVal’ĶĶ’’’’ĶĶĶͬDMsg ’ĶĶ’’’’ĶĶĶͰF SetUp Æ ­ ’ĶĶ’’’’ĶĶĶĶ®Imsg ’ĶĶ’’’’ĶĶĶĶ™M PathPerformance ² ’ĶĶ’’’’ĶĶĶͳ?PathPerfDiag€(' “  µ _ ¶ ’ĶĶ’’’’ĶĶĶĶ·DImpPathList Õ (ImplementationPaths’ĶĶ’’’’ĶĶĶ͹DNumberOfUsers ø ’ĶĶ’’’’ĶĶĶĶ»DPathFactor ŗ ’ĶĶ’’’’ĶĶĶͼD ResourceBoxList å ’ĶĶ’’’’ĶĶĶͽDActionBoxList ć ’ĶĶ’’’’ĶĶĶ;DLastElement ' ’ĶĶ’’’’ĶĶĶĶæDPathStartList į ’ĶĶ’’’’ĶĶĶĶĮDClicksPerLoop Ą ’ĶĶ’’’’ĶĶĶĶĀDTokenStartList ß ’ĶĶ’’’’ĶĶĶĶÄDTokenStartInx Ć ’ĶĶ’’’’ĶĶĶĶĘDLoopNumber Å ’ĶĶ’’’’ĶĶĶĶĒDStartSeconds’ĶĶ’’’’ĶĶĶĶČDSeconds  ’ĶĶ’’’’ĶĶĶĶÉDTokensStarted  ’ĶĶ’’’’ĶĶĶĶŹDTokensEnded  ’ĶĶ’’’’ĶĶĶĶĖDTotalElapsed’ĶĶ’’’’ĶĶĶĶĢDElapsedAvg  ’ĶĶ’’’’ĶĶĶĶĶDElapsedMax  ’ĶĶ’’’’ĶĶĶĶĪDMoveTokenList Ż ’ĶĶ’’’’ĶĶĶĶĻDMainHorz U ’ĶĶ’’’’ĶĶĶĶŠDBarChart ” ’ĶĶ’’’’ĶĶĶĶŅDNoUtilsCount Ń ’ĶĶ’’’’ĶĶĶĶÕFBuildDisplay Ō Ó ’ĶĶ’’’’ĶĶĶĶŻFBuildPath Ü Ö ’ĶĶ’’’’ĶĶĶĶ×Ial Ū ’ĶĶ’’’’ĶĶĶĶŲIst I’ĶĶ’’’’ĶĶĶĶŁI above’ĶĶ’’’’ĶĶĶĶŚInum’ĶĶ’’’’ĶĶĶĶŪI subno’ĶĶ’’’’ĶĶĶĶäFAddResource M  ć Ž ’ĶĶ’’’’ĶĶĶĶßIut 9 ’ĶĶ’’’’ĶĶĶĶąIbx H’ĶĶ’’’’ĶĶĶĶįI above’ĶĶ’’’’ĶĶĶĶāInum’ĶĶ’’’’ĶĶĶĶčFSetNext ē å ’ĶĶ’’’’ĶĶĶĶęIal ' ’ĶĶ’’’’ĶĶĶĶėFSetUpIterate ~ ź é üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüVö+YRĒmT’ĶĶ’’’’ĶĶĶĶīFIterate ~ ķ ģ ’ĶĶ’’’’ĶĶĶĶóFDetachToken ņ ļ ’ĶĶ’’’’ĶĶĶĶšIt  ’ĶĶ’’’’ĶĶĶĶńItm’ĶĶ’’’’ĶĶĶĶųFFinishAction ÷ ō ’ĶĶ’’’’ĶĶĶĶõIt  ’ĶĶ’’’’ĶĶĶĶöItm’ĶĶ’’’’ĶĶĶĶ’F,FinishActionAndDelete ž ł ’ĶĶ’’’’ĶĶĶĶśIt  ’ĶĶ’’’’ĶĶĶĶūItm’ĶĶ’’’’ĶĶĶĶüIorigtoken  ’ĶĶ’’’’ĶĶĶĶżI subno’ĶĶ’’’’ĶĶĶĶFNewToken     ’ĶĶ’’’’ĶĶĶĶItm’ĶĶ’’’’ĶĶĶĶFAttachToken   ’ĶĶ’’’’ĶĶĶĶIt  ’ĶĶ’’’’ĶĶĶĶItm’ĶĶ’’’’ĶĶĶĶ ? Token€)'     Ü ’ĶĶ’’’’ĶĶĶĶ DAction ' ’ĶĶ’’’’ĶĶĶĶ D ClicksRemaining’ĶĶ’’’’ĶĶĶĶDStartTime’ĶĶ’’’’ĶĶĶĶDMaster  ’ĶĶ’’’’ĶĶĶĶD StartActionTime’ĶĶ’’’’ĶĶĶĶDSuspended  ’ĶĶ’’’’ĶĶĶĶ?TokenStart€*'     Ž ’ĶĶ’’’’ĶĶĶĶD Time’ĶĶ’’’’ĶĶĶĶDFirstAction ' ’ĶĶ’’’’ĶĶĶĶF SetUp   ’ĶĶ’’’’ĶĶĶĶIfa ' ’ĶĶ’’’’ĶĶĶĶItotalClicks’ĶĶ’’’’ĶĶĶĶ?PathStart€+'     ą ’ĶĶ’’’’ĶĶĶĶ DNumber’ĶĶ’’’’ĶĶĶĶ!DFirstAction ' ’ĶĶ’’’’ĶĶĶĶ&F SetUp % " ’ĶĶ’’’’ĶĶĶĶ#Ifa ' ’ĶĶ’’’’ĶĶĶĶ$In’ĶĶ’’’’ĶĶĶĶ'?ActionBoxBase€,' (  )  * ³  ā ’ĶĶ’’’’ĶĶĶĶ+D Next ' ’ĶĶ’’’’ĶĶĶĶ,DResourceBoxes å ’ĶĶ’’’’ĶĶĶĶ-DDataObject D ’ĶĶ’’’’ĶĶĶĶ/DCummulativeET . ’ĶĶ’’’’ĶĶĶĶ1DNumTokens 0 ’ĶĶ’’’’ĶĶĶĶ3DHasSubActions 2 ’ĶĶ’’’’ĶĶĶĶ4DSubNumber’ĶĶ’’’’ĶĶĶĶ5D Title ’ĶĶ’’’’ĶĶĶĶ<F SetUp ; 6 ’ĶĶ’’’’ĶĶĶĶ7Iia D ’ĶĶ’’’’ĶĶĶĶ8I above’ĶĶ’’’’ĶĶĶĶ9Inum’ĶĶ’’’’ĶĶĶĶ:I subno’ĶĶ’’’’ĶĶĶĶ=?ActionBox€-' >  “’ĶĶ’’’’ĶĶĶĶ??ActionMsgBox€.' @  Ø’ĶĶ’’’’ĶĶĶĶA?ActionStripe€/' B  C – D ³ ’ĶĶ’’’’ĶĶĶĶEDDataObject D ’ĶĶ’’’’ĶĶĶĶLF SetUp K F ’ĶĶ’’’’ĶĶĶĶGIia D ’ĶĶ’’’’ĶĶĶĶHI above’ĶĶ’’’’ĶĶĶĶIInum’ĶĶ’’’’ĶĶĶĶJI subno’ĶĶ’’’’ĶĶĶĶM?ResourceBox€0' N  O ™ P ³  ä ’ĶĶ’’’’ĶĶĶĶQDDataObject ) ’ĶĶ’’’’ĶĶĶĶSDUnitsUsed R ’ĶĶ’’’’ĶĶĶĶTDUnitsAvail’ĶĶ’’’’ĶĶĶĶUDClicksUsed’ĶĶ’’’’ĶĶĶĶVDClicksAvail’ĶĶ’’’’ĶĶĶĶWDClicksBase’ĶĶ’’’’ĶĶĶĶXDUnitsToClicks’ĶĶ’’’’ĶĶĶĶZDClicky Y ’ĶĶ’’’’ĶĶĶĶ\DBaseUnitsUsed [ ’ĶĶ’’’’ĶĶĶĶ]DStatsY’ĶĶ’’’’ĶĶĶĶ_DStatsHeight ^ ’ĶĶ’’’’ĶĶĶĶaD"ControlsDuration ` ’ĶĶ’’’’ĶĶĶĶbD$ClicksDoSomethingüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüoć<ņ㜪P’ĶĶ’’’’ĶĶĶĶcD Title ’ĶĶ’’’’ĶĶĶĶdDActiveTokens Ż ’ĶĶ’’’’ĶĶĶĶfD"ActiveTokenCount e ’ĶĶ’’’’ĶĶĶĶgDIsQueued’ĶĶ’’’’ĶĶĶĶkF SetUp j h ’ĶĶ’’’’ĶĶĶĶiIr ) ’ĶĶ’’’’ĶĶĶĶnFSetStatsHeight m l ’ĶĶ’’’’ĶĶĶĶuFAddAction t o ’ĶĶ’’’’ĶĶĶĶpIut 9 ’ĶĶ’’’’ĶĶĶĶqInum’ĶĶ’’’’ĶĶĶĶrIbx H’ĶĶ’’’’ĶĶĶĶsI above’ĶĶ’’’’ĶĶĶĶxF QueueModelClear w v ’ĶĶ’’’’ĶĶĶĶ}F"QueueModelChange | y ’ĶĶ’’’’ĶĶĶĶzIia D ’ĶĶ’’’’ĶĶĶĶ{Iadduse’ĶĶ’’’’ĶĶĶĶ€FSetDoSomething  ~ ’ĶĶ’’’’ĶĶĶ́?ResourceConn€1' ‚  ƒ œ „ ’ĶĶ’’’’ĶĶĶ͊F SetUp ‰ … ’ĶĶ’’’’ĶĶĶ͆Ia H’ĶĶ’’’’ĶĶĶ͇Ir M ’ĶĶ’’’’ĶĶĶ͈I above’ĶĶ’’’’ĶĶĶĶ‹?"SimpleDirectConn€2' Œ   „ Ž ’ĶĶ’’’’ĶĶĶĶ“F SetUp ’  ’ĶĶ’’’’ĶĶĶ͐Ist H’ĶĶ’’’’ĶĶĶĶ‘Ien H’ĶĶ’’’’ĶĶĶĶ”?MetricShape€3' •  – < — ’ĶĶ’’’’ĶĶĶ͘D Title ’ĶĶ’’’’ĶĶĶͰM RandomnessChart š ’ĶĶ’’’’ĶĶĶĶ›? RandomnessChart€4' œ    ž ’ĶĶ’’’’ĶĶĶĶ D Slots Ÿ ’ĶĶ’’’’ĶĶĶĶ¢DThings ” ’ĶĶ’’’’ĶĶĶĶ£DSlotsList n’ĶĶ’’’’ĶĶĶĶ„DIsPseudo ¤ ’ĶĶ’’’’ĶĶĶͧDPseudoSeed ¦ ’ĶĶ’’’’ĶĶĶĶŖFBuildDisplay © Ø ’ĶĶ’’’’ĶĶĶĶ«?VertBarShape€5' ¬  ­ ? ® ’ĶĶ’’’’ĶĶĶĶÆD Title ’ĶĶ’’’’ĶĶĶĶŹM(GuideDiagramSupport ± ’ĶĶ’’’’ĶĶĶͲ?"StripeVertFigure€6' ³  ß’ĶĶ’’’’ĶĶĶĶ“? LayerRectFigure€7' µ  ¶ Ś · ’ĶĶ’’’’ĶĶĶĶøD Title ’ĶĶ’’’’ĶĶĶ͹?ServerDBFigure€8' ŗ  » Ō ¼ ’ĶĶ’’’’ĶĶĶͽD Title ’ĶĶ’’’’ĶĶĶ;?RoundedFigure€9' æ  Ą × Į ’ĶĶ’’’’ĶĶĶĶĀD Title ’ĶĶ’’’’ĶĶĶĶĆ?DiskFigure€:' Ä  Å ų Ę ’ĶĶ’’’’ĶĶĶĶĒD Title ’ĶĶ’’’’ĶĶĶĶČ?LineFigure€;' É  Ż’ĶĶ’’’’ĶĶĶĶĻMGuideGroup Ģ ’ĶĶ’’’’ĶĶĶĶĶ? Guide€<' Ī ’ĶĶ’’’’ĶĶĶĶŃR"Performance Path _’ĶĶ’’’’ĶĶĶĶŅR"Randomness Chart ø’ĶĶ’’’’ĶĶĶĶŌ@,ImplementationPathSet€='   ’ĶĶ’’’’ĶĶĶĶÕ@.ImplementationPathList€>'   ’ĶĶ’’’’ĶĶĶĶ×@ITResourceSet€?'  ) ’ĶĶ’’’’ĶĶĶĶŁ@ UtilResourceSet€@'  9 ’ĶĶ’’’’ĶĶĶĶŪ@ImpActionList€A'  D ’ĶĶ’’’’ĶĶĶĶŻ@TokenList€B'   ’ĶĶ’’’’ĶĶĶĶß@TokenStartList€C'   ’ĶĶ’’’’ĶĶĶĶį@PathStartList€D'   ’ĶĶ’’’’ĶĶĶĶć@$ActionBoxBaseList€E'  ' ’ĶĶ’’’’ĶĶĶĶå@ ResourceBoxList€F'  M ’ĶĶ’’’’ĶĶĶĶķ¬ProcStyle£££üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü rA·/Pöō’ĶĶ’’’’ĶĶĶĶī¬(WhiteFillGreyBorder’’’ddd€?’ĶĶ’’’’ĶĶĶĶļ¬DBFigFillStyleü€’ĶĶ’’’’ĶĶĶĶš¬DBFigFullStyleü€É3€?’ĶĶ’’’’ĶĶĶĶń¬"ActivityBoxStyleļ¶?€?’ĶĶ’’’’ĶĶĶĶņ¬$UpperWarningStyle’’ĶĶ’’’’ĶĶĶĶó¬$LowerWarningStyle’’ĶĶ’’’’ĶĶĶĶō¬StatsBoxStyle’’ĶĶ’’’’ĶĶĶĶõ¬GreyArrowStyle––––––€? ö ’ĶĶ’’’’ĶĶĶĶöÆffÖ@€@’ĶĶ’’’’ĶĶĶĶ÷¬,BoxBagConnDoubleStyle––––––@@ ų  ł ’ĶĶ’’’’ĶĶĶĶųÆ33S@@’ĶĶ’’’’ĶĶĶĶłÆ33S@@’ĶĶ’’’’ĶĶĶĶś¬&BoxBagConnRedStyle’€? ū ’ĶĶ’’’’ĶĶĶĶūÆffÖ@€@’ĶĶ’’’’ĶĶĶĶü¬"ServiceCallStyle’€? ż ’ĶĶ’’’’ĶĶĶĶżÆffÖ@€@’ĶĶ’’’’ĶĶĶĶž¬.BoxBagConnNoArrowStyle–––€?’ĶĶ’’’’ĶĶĶĶ’¬$ExternalConnStyle’€?    ’ĶĶ’’’’ĶĶĶĶÆffÖ@€@’ĶĶ’’’’ĶĶĶĶÆffÖ@€@’ĶĶ’’’’ĶĶĶͬAppTopStyle’ČČ’’’’ĶĶ’’’’ĶĶĶͬAppMidStyleČ’Č’’’’ĶĶ’’’’ĶĶĶͬAppBotStyleČČ’’’’’ĶĶ’’’’ĶĶĶͬ"InfoBagRectStyleČ’Č’ĶĶ’’’’ĶĶĶͬEventStyle’ĶĶ’’’’ĶĶĶͬEndEventStyle€?’ĶĶ’’’’ĶĶĶͬSeqStyle  ’ĶĶ’’’’ĶĶĶĶ Æ€@€@’ĶĶ’’’’ĶĶĶĶ ¬AndLineStyle@@’ĶĶ’’’’ĶĶĶĶ ¬&AttributeListStyle’’’’ĶĶ’’’’ĶĶĶĶ ¬"SubtypeRakeStyle  ’ĶĶ’’’’ĶĶĶĶ ÆAA’ĶĶ’’’’ĶĶĶͬ ForeignKeyStyle’ĶĶ’’’’ĶĶĶͬ$SessionGroupStyleÜÜ’’ĶĶ’’’’ĶĶĶͬHighLightStyle’’ A?’ĶĶ’’’’ĶĶĶͬDoneLightStyle’ A?’ĶĶ’’’’ĶĶĶͬActionBoxStyleļ“<€?’ĶĶ’’’’ĶĶĶͬ$ActionStripeStyle€?’ĶĶ’’’’ĶĶĶͬ"ResourceBoxStyleČČ’€?’ĶĶ’’’’ĶĶĶͬ WorkActionStyledd’’ĶĶ’’’’ĶĶĶͬ LineFigureStyle€?’ĶĶ’’’’ĶĶĶĶ«HeadMsgStyle`A’ĶĶ’’’’ĶĶĶĶ«SmallNamesA’ĶĶ’’’’ĶĶĶĶ«NameStyle A’ĶĶ’’’’ĶĶĶĶ«NameStyleBold A’ĶĶ’’’’ĶĶĶĶ«NameStyleLeft A’ĶĶ’’’’ĶĶĶĶ«TitleStyle A’’ĶĶ’’’’ĶĶĶĶ«Info_TextStyleĄ@’ĶĶ’’’’ĶĶĶĶ«Info_TextStyle A’’’’ĶĶ’’’’ĶĶĶĶģ^’ĶĶ’’’’ĶĶĶĶėJ’ĶĶ’’’’ĶĶĶĶźQ’ĶĶ’’’’ĶĶĶĶéO’ĶĶ’’’’ĶĶĶĶčH’ĶĶ’’’’ĶĶĶĶēb)ķ ī ļ š ń ņ ó ō õ ÷ ś ü ž ’                            ’ĶĶ’’’’ĶĶĶĶä@å ’ĶĶ’’’’ĶĶĶĶā@ć ’ĶĶ’’’’ĶĶĶĶą@į ’ĶĶ’’’’ĶĶĶĶŽ@ß ’ĶĶ’’’’ĶĶĶĶÜ@Ż ’ĶĶ’’’’ĶĶĶĶŚ@Ū ’ĶĶ’’’’ĶĶĶĶŲ@Ł ’ĶĶ’’’’ĶĶĶĶÖ@× ’ĶĶ’’’’ĶĶĶĶÓ@Ō Õ üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüqXóÕoį’ĶĶ’’’’ĶĶĶĶŠAŃ Ņ ’ĶĶ’’’’ĶĶĶĶĪB`’ĶĶ’’’’ĶĶĶĶĢ@Ķ ’ĶĶ’’’’ĶĶĶĶĖGĻ ’ĶĶ’’’’ĶĶĶĶÉBN’ĶĶ’’’’ĶĶĶĶĘD’ĶĶ’’’’ĶĶĶĶÅCĒ ’ĶĶ’’’’ĶĶĶĶÄBH’ĶĶ’’’’ĶĶĶĶĮD’ĶĶ’’’’ĶĶĶĶĄCĀ ’ĶĶ’’’’ĶĶĶĶæBH’ĶĶ’’’’ĶĶĶͼD’ĶĶ’’’’ĶĶĶĶ»C½ ’ĶĶ’’’’ĶĶĶĶŗBH’ĶĶ’’’’ĶĶĶĶ·D’ĶĶ’’’’ĶĶĶͶCø ’ĶĶ’’’’ĶĶĶ͵BH’ĶĶ’’’’ĶĶĶͳBI’ĶĶ’’’’ĶĶĶͱ@² “ ¹ ¾ Ć Č ’ĶĶ’’’’ĶĶĶĶ®D’ĶĶ’’’’ĶĶĶĶ­CÆ ’ĶĶ’’’’ĶĶĶͬBR’ĶĶ’’’’ĶĶĶĶØE’ĶĶ’’’’ĶĶĶĶžD’ĶĶ’’’’ĶĶĶĶC  ¢ £ „ § Ŗ ’ĶĶ’’’’ĶĶĶ͜BD’ĶĶ’’’’ĶĶĶ͚@› « ’ĶĶ’’’’ĶĶĶĶ—D’ĶĶ’’’’ĶĶĶĶ–C˜ ’ĶĶ’’’’ĶĶĶĶ•BR’ĶĶ’’’’ĶĶĶĶE ‘ ’ĶĶ’’’’ĶĶĶĶŽD’ĶĶ’’’’ĶĶĶĶC“ ’ĶĶ’’’’ĶĶĶ͌BN’ĶĶ’’’’ĶĶĶĶ…E† ‡ ˆ ’ĶĶ’’’’ĶĶĶĶ„D’ĶĶ’’’’ĶĶĶ̓CŠ ’ĶĶ’’’’ĶĶĶĶ‚BN’ĶĶ’’’’ĶĶĶĶ~E’ĶĶ’’’’ĶĶĶĶyEz { ’ĶĶ’’’’ĶĶĶĶvE’ĶĶ’’’’ĶĶĶĶoEp q r s ’ĶĶ’’’’ĶĶĶĶlE’ĶĶ’’’’ĶĶĶĶhEi ’ĶĶ’’’’ĶĶĶĶPD’ĶĶ’’’’ĶĶĶĶOCQ S T U V W X Z \ ] _ a b c d f g k n u x } € ’ĶĶ’’’’ĶĶĶĶNB[ ’ĶĶ’’’’ĶĶĶĶFEG H I J ’ĶĶ’’’’ĶĶĶĶDD’ĶĶ’’’’ĶĶĶĶCCE L ’ĶĶ’’’’ĶĶĶĶBBd ’ĶĶ’’’’ĶĶĶĶ@B' ’ĶĶ’’’’ĶĶĶĶ>B' ’ĶĶ’’’’ĶĶĶĶ6E7 8 9 : ’ĶĶ’’’’ĶĶĶĶ*D’ĶĶ’’’’ĶĶĶĶ)C + , - / 1 3 4 5 < ’ĶĶ’’’’ĶĶĶĶ(B[ ’ĶĶ’’’’ĶĶĶĶ"E# $ ’ĶĶ’’’’ĶĶĶĶD’ĶĶ’’’’ĶĶĶĶC  ! & ’ĶĶ’’’’ĶĶĶĶE  ’ĶĶ’’’’ĶĶĶĶD’ĶĶ’’’’ĶĶĶĶC   ’ĶĶ’’’’ĶĶĶĶ D’ĶĶ’’’’ĶĶĶĶ C       ’ĶĶ’’’’ĶĶĶĶE  ’ĶĶ’’’’ĶĶĶĶE ’ĶĶ’’’’ĶĶĶĶłEś ū ü ż ’ĶĶ’’’’ĶĶĶĶōEõ ö ’ĶĶ’’’’ĶĶĶĶļEš ń ’ĶĶ’’’’ĶĶĶĶģE’ĶĶ’’’’ĶĶĶĶéE’ĶĶ’’’’ĶĶĶĶåEę ’ĶĶ’’’’ĶĶĶĶŽEß ą į ā ’ĶĶ’’’’ĶĶĶĶÖE× Ų Ł Ś Ū ’ĶĶ’’’’ĶĶĶĶÓE’ĶĶ’’’’ĶĶĶͶD’ĶĶ’’’’ĶĶĶ͵C!· ¹ » ¼ ½ ¾ æ Į Ā Ä Ę Ē Č É Ź Ė Ģ Ķ Ī Ļ Š Ņ Õ Ż ä č ė ī ó ų ’   ’ĶĶ’’’’ĶĶĶĶ“BD’ĶĶ’’’’ĶĶĶͲ@ ³    ' = ? A M  ‹ ” ’ĶĶ’’’’ĶĶĶĶ­E® ’ĶĶ’’’’ĶĶĶĶŖD’ĶĶ’’’’ĶĶĶĶ©C« ¬ ° ’ĶĶ’’’’ĶĶĶĶØBŒ ’ĶĶ’’’’ĶĶĶĶ£E¤ üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüėņŚœl%©’ĶĶ’’’’ĶĶĶĶ D’ĶĶ’’’’ĶĶĶ͟C” ¢ ¦ ’ĶĶ’’’’ĶĶĶĶžBŒ ’ĶĶ’’’’ĶĶĶ͜BŒ ’ĶĶ’’’’ĶĶĶĶ—E˜ ’ĶĶ’’’’ĶĶĶĶ•D’ĶĶ’’’’ĶĶĶĶ”C– š ’ĶĶ’’’’ĶĶĶĶ“BŒ ’ĶĶ’’’’ĶĶĶĶD’ĶĶ’’’’ĶĶĶĶŽC‘ ’ĶĶ’’’’ĶĶĶĶBH’ĶĶ’’’’ĶĶĶ͈E‰ ’ĶĶ’’’’ĶĶĶ͇D’ĶĶ’’’’ĶĶĶ͆C‹ ’ĶĶ’’’’ĶĶĶĶ…BI’ĶĶ’’’’ĶĶĶ́F‚ ƒ ’ĶĶ’’’’ĶĶĶĶ|E} ’ĶĶ’’’’ĶĶĶĶxEy ’ĶĶ’’’’ĶĶĶĶtEu ’ĶĶ’’’’ĶĶĶĶpD’ĶĶ’’’’ĶĶĶĶoCq r s w {  ’ĶĶ’’’’ĶĶĶĶnBH’ĶĶ’’’’ĶĶĶĶiEj ’ĶĶ’’’’ĶĶĶĶgD’ĶĶ’’’’ĶĶĶĶfCh l ’ĶĶ’’’’ĶĶĶĶeBI’ĶĶ’’’’ĶĶĶĶ`Ea ’ĶĶ’’’’ĶĶĶĶ^D’ĶĶ’’’’ĶĶĶĶ]C_ c ’ĶĶ’’’’ĶĶĶĶ\BH’ĶĶ’’’’ĶĶĶĶZBI’ĶĶ’’’’ĶĶĶĶXBI’ĶĶ’’’’ĶĶĶĶVBI’ĶĶ’’’’ĶĶĶĶT@ U W Y [ d m € „ Œ ’ ›  § ’ĶĶ’’’’ĶĶĶĶSG± ™ ° Ź ’ĶĶ’’’’ĶĶĶĶQBD ’ĶĶ’’’’ĶĶĶĶOBD ’ĶĶ’’’’ĶĶĶĶGDM ’ĶĶ’’’’ĶĶĶĶFCH I K ’ĶĶ’’’’ĶĶĶĶEB ’ĶĶ’’’’ĶĶĶĶ;D’ĶĶ’’’’ĶĶĶĶ:C< > @ B C ’ĶĶ’’’’ĶĶĶĶ5F6 7 8 ’ĶĶ’’’’ĶĶĶĶ,D’ĶĶ’’’’ĶĶĶĶ+C. 0 2 3 ’ĶĶ’’’’ĶĶĶĶ*B ’ĶĶ’’’’ĶĶĶĶ%F& ' ( ’ĶĶ’’’’ĶĶĶĶ F! " # ’ĶĶ’’’’ĶĶĶĶD’ĶĶ’’’’ĶĶĶĶC    ’ĶĶ’’’’ĶĶĶĶB ’ĶĶ’’’’ĶĶĶĶD’ĶĶ’’’’ĶĶĶĶC   ’ĶĶ’’’’ĶĶĶĶ E  ’ĶĶ’’’’ĶĶĶĶE’ĶĶ’’’’ĶĶĶĶD ’ĶĶ’’’’ĶĶĶĶC   ’ĶĶ’’’’ĶĶĶĶBA’ĶĶ’’’’ĶĶĶĶ@     $ ) 4 9 D N P ’ĶĶ’’’’ĶĶĶĶGR ’ĶĶ’’’’ĶĶĶĶę<The Polyphony model is copyright (c) 2008, Polyphony IT, UK.’ĶĶ’’’’ĶĶĶĶ ‘repeat Slots do SlotsList append 0; endrepeat; locals titlebox := new TitleBox call SetUp("Randomness Test"); bar := new VertBarShape; n := 0; itb := new InfoTextBox; slots := new IntInfoTextLine call SetUp("Number of slots = "); things := new IntInfoTextLine call SetUp("Number of things to put in the slots = "); maxinslot := new IntInfoTextLine call SetUp("Maximum in a slot = "); mininslot := new IntInfoTextLine call SetUp("Minumum in a slot = "); mn := high_int(); mx := 0; do if IsPseudo then set_prandom_seed(PseudoSeed); repeat Things do n := iprandom(Slots); ņ‘šQG[b ’ĶĶ’’’’ĶĶĶĶ!SlotsList [n] := SlotsList [n] + 1; endrepeat; else repeat Things do n := irandom(Slots); SlotsList [n] := SlotsList [n] + 1; endrepeat; endif; titlebox.Left := 200; titlebox.Top := 50; Shapes append titlebox; Shapes append bar; bar.Title := "Slots"; bar.Left := 200; bar.Top := 250; for s := SlotsList do bar.Data append _namenumber{str(s), s}; mn := min(mn, s); mx := max(mx, s); endfor; itb.Left := 10; itb.Top := 100; Shapes append itb; slots.Val := Slots; itb.Add(slots); things.Val := Things; itb.Add(things); maxinslot.Val := mx; itb.Add(maxinslot); mininslot.Val := mn; itb.Add(mininslot); endlocals; ’ĶĶ’’’’ĶĶĶĶ©‘  ! ’ĶĶ’’’’ĶĶĶͦ1’ĶĶ’’’’ĶĶĶͤfalse’ĶĶ’’’’ĶĶĶĶ”100’ĶĶ’’’’ĶĶĶ͟10’ĶĶ’’’’ĶĶĶĶ’StartBox := st; EndBox := en; ’ĶĶ’’’’ĶĶĶ͉‘StartBox := a; EndBox := r; if above then StartSide := Bottom; EndSide := Top; else StartSide := Top; EndSide := Bottom; endif; ’ĶĶ’’’’ĶĶĶĶųlocals cr := high_float(); do if IsQueued then for t := head(ActiveTokens, DataObject.Number) where not t.Suspended do cr := min(cr, t.ClicksRemaining); endfor; ClicksDoSomething := cr; else for t := ActiveTokens where not t.Suspended do cr := min(cr, t.ClicksRemaining); endfor; ClicksDoSomething := cr * ActiveTokenCount; endif; if cr = high_float() then ControlsDuration := false; endif; endlocals; ’ĶĶ’’’’ĶĶĶĶ|_for u := ia.Utils do if u.Resource = DataObject then if adduse then UnitsUsed := UnitsUsed + u.UnitsUtil; ActiveTokenCount := ActiveTokenCount + 1; else UnitsUsed := UnitsUsed - u.UnitsUtil; ActiveTokenCount := ActiveTokenCount - 1; endif; return; endif; endfor; üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü"x.¢Ž]} ’ĶĶ’’’’ĶĶĶĶwif StatsHeight >= 50 then locals di := DrawItems << "util" >>; do di.SetStyle("StatsBoxStyle"); endlocals; endif; StatsHeight := 0; StatsY := 70; if DataObject.Category = eFixed then UnitsUsed := BaseUnitsUsed; else ClicksUsed := 0; ClicksAvail := context.ClicksPerLoop; ClicksBase := BaseUnitsUsed * context.ClicksPerLoop / UnitsAvail; UnitsToClicks := ClicksAvail / UnitsAvail; UnitsToClicks := UnitsToClicks * ClicksAvail / (ClicksAvail - ClicksBase); Clicky := true; endif; ’ĶĶ’’’’ĶĶĶĶtėlocals extrabase := ut.BackgroundUnits + ut.UtilByUser * context.NumberOfUsers; do BaseUnitsUsed := BaseUnitsUsed + extrabase; UnitsUsed := UnitsUsed + ut.UnitsUtil * num + extrabase; endlocals; if isnull UnitsAvail then locals di := DrawItems << "util" >>; do di.SetStyle("LowerWarningStyle"); endlocals; StatsHeight := 50; StatsY := 70 - StatsHeight; else SetStatsHeight(); endif; context.Shapes append new ResourceConn call SetUp(bx, this, above); ’ĶĶ’’’’ĶĶĶĶm}if DataObject.Category = eFixed and isnull UnitsAvail then return; endif; locals oldht := StatsHeight; do if Clicky then StatsHeight := ClicksUsed * 50 / ClicksAvail; else StatsHeight := UnitsUsed * 50 / UnitsAvail; endif; if StatsHeight >= 50 and oldht < 50 then locals di := DrawItems << "util" >>; do di.SetStyle("UpperWarningStyle"); endlocals; elseif oldht >= 50 and StatsHeight < 50 then locals di := DrawItems << "util" >>; do di.SetStyle("StatsBoxStyle"); endlocals; endif; endlocals; StatsY := 70 - StatsHeight; ’ĶĶ’’’’ĶĶĶĶj&DataObject := r; Title := r.Name; IsQueued := r.Category = eQueued; if IsQueued then DisplayControl := flag(eQueued); elseif r.Category = eTimesliced then DisplayControl := flag(eTimesliced); endif; if notnull r.Units then UnitsAvail := DataObject.Units * DataObject.Number; endif; üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüyžz3ńłł£ ’ĶĶ’’’’ĶĶĶĶe0’ĶĶ’’’’ĶĶĶĶ`false’ĶĶ’’’’ĶĶĶĶ^0’ĶĶ’’’’ĶĶĶĶ[0’ĶĶ’’’’ĶĶĶĶYfalse’ĶĶ’’’’ĶĶĶĶR0’ĶĶ’’’’ĶĶĶĶKŃDataObject := ia; locals ab := new ActionBox call SetUp(ia, above, num, subno); do Shapes append ab; ab.HasSubActions := true; endlocals; context.BuildPath(ia.SubActions, this, above, num, subno + 1); ’ĶĶ’’’’ĶĶĶĶ;ŌDataObject := ia; Title := ia.Name; for ut := ia.Utils do ResourceBoxes append context.AddResource(ut, this, above, num); endfor; context.SetNext(this); context.ActionBoxList append this; SubNumber := subno; ’ĶĶ’’’’ĶĶĶĶ2false’ĶĶ’’’’ĶĶĶĶ00’ĶĶ’’’’ĶĶĶĶ.0’ĶĶ’’’’ĶĶĶĶ% FirstAction := fa; Number := n; ’ĶĶ’’’’ĶĶĶĶ2FirstAction := fa; Time := iprandom(totalClicks); ’ĶĶ’’’’ĶĶĶĶfalse’ĶĶ’’’’ĶĶĶĶt.StartActionTime := Seconds.Val * ClicksPerLoop + tm; locals cnt := 0; ia := t.Action.DataObject; do for r := t.Action.ResourceBoxes do if r.DataObject.Category = eFixed then r.QueueModelChange(ia, true); else r.ActiveTokens append t; r.ActiveTokenCount := r.ActiveTokenCount + 1; r.ControlsDuration := true; cnt := cnt + 1; locals x := find u := ia.Utils where u.Resource = r.DataObject endfind; do t.ClicksRemaining := x.UnitsUtil * r.UnitsToClicks; if t.ClicksRemaining <= 0 then stop "Action has resource without UnitsUtil set"; endif; endlocals; r.SetDoSomething(); endif; endfor; if cnt <> 1 then stop "Each action must have one resource that controls its duration"; endif; endlocals; ’ĶĶ’’’’ĶĶĶĶølocals tk := new Token; do TokensStarted.Val := TokensStarted.Val + 1; tk.StartTime := ClicksPerLoop * Seconds.Val + tm; MoveTokenList append tk; return tk; endlocals; ’ĶĶ’’’’ĶĶĶĶ"›if notnull t.Master then if t.Master.Action.SubNumber < subno then origtoken.Master := t.Master; else FinishActionAndDelete(t.Mastü捑cr.½  ’ĶĶ’’’’ĶĶĶĶ#oer, tm, origtoken, subno); endif; else origtoken.Master := null; endif; FinishAction(t, tm); delete t; ’ĶĶ’’’’ĶĶĶĶž›" o# ’ĶĶ’’’’ĶĶĶĶ÷0t.Action.CummulativeET := t.Action.CummulativeET + Seconds.Val * ClicksPerLoop + tm - t.StartActionTime; t.Action.NumTokens := t.Action.NumTokens + 1; for r := t.Action.ResourceBoxes do if r.DataObject.Category = eFixed then r.QueueModelChange(t.Action.DataObject, false); else locals cnt := 0; do update rtoks := r.ActiveTokens do if rtoks = t then remove rtoks; r.ActiveTokenCount := r.ActiveTokenCount - 1; else cnt := cnt + 1; endif; endupdate; if cnt = 0 then r.ControlsDuration := false; else r.SetDoSomething(); endif; endlocals; endif; endfor; ’ĶĶ’’’’ĶĶĶĶņ¦if t.Action.HasSubActions then t.Suspended := true; locals newtok := new Token; do MoveTokenList append newtok; newtok.Action := t.Action.Next; newtok.Master := t; newtok.StartTime := t.StartTime; endlocals; return; endif; FinishAction(t, tm); if isnull t.Action.Next then if notnull t.Master then FinishActionAndDelete(t.Master, tm, t, 0); endif; locals el := Seconds.Val * ClicksPerLoop + tm - t.StartTime; do TokensEnded.Val := TokensEnded.Val + 1; TotalElapsed := TotalElapsed + el; ElapsedAvg.Val := round(TotalElapsed / TokensEnded.Val); ElapsedMax.Val := max(ElapsedMax.Val, round(el)); delete t; endlocals; return; endif; if t.Action.SubNumber > t.Action.Next.SubNumber then FinishActionAndDelete(t.Master, tm, t, t.Action.Next.SubNumber); endif; MoveTokenList append t; t.Action := t.Action.Next; ’ĶĶ’’’’ĶĶĶĶ$`Seconds.Val := Seconds.Val + 1; for r := ResourceBoxList where r.DataObject.Category <> eFixed düņŠ šę“u} ’ĶĶ’’’’ĶĶĶĶ%éo r.ClicksUsed := r.ClicksBase; endfor; loop x float := 0; y float; do y := ClicksPerLoop - x; for r := ResourceBoxList where r.ControlsDuration do y := min(y, r.ClicksDoSomething); endfor; if TokenStartInx < count(TokenStartList) then locals tm := ClicksPerLoop * LoopNumber + x; ts := TokenStartList [TokenStartInx]; st := ts.Time; do if (st - tm) <= y then y := st - tm; loop do locals newtok := new Token; do TokensStarted.Val := TokensStarted.Val + 1; newtok.StartTime := ClicksPerLoop * Seconds.Val + x + y; MoveTokenList append newtok; newtok.Action := ts.FirstAction; endlocals; TokenStartInx := TokenStartInx + 1; break : TokenStartInx >= count(TokenStartList); ts := TokenStartList [TokenStartInx]; break : ts.Time <> st; endloop; endif endlocals; endif; y := max(y, 1); for r := ResourceBoxList where r.ControlsDuration do r.ClicksDoSomething := r.ClicksDoSomething - y; r.ClicksUsed := r.ClicksUsed + y; endfor; for r := ResourceBoxList where r.ControlsDuration do if r.IsQueued then r.ClicksDoSomething := ClicksPerLoop; for a := head(r.ActiveTokens, r.DataObject.Number) where not a.Suspended do a.ClicksRemaining := a.ClicksRemaining - y; if a.ClicksRemaining <= 0 then DetachToken(a, x + y); else r.ClicksDoSomething := min(r.ClicksDoSomething, a.ClicksRemaining); endif; endfor; if r.ActiveTokenCount = 0 then r.ControlsDuration := false; endif; else locals actüē¹Č%9K’ĶĶ’’’’ĶĶĶĶ&Acnt := count(for at := r.ActiveTokens where not at.Suspended endfor); do if actcnt > 0 then locals slice := y / actcnt; cds := high_float(); do for a := r.ActiveTokens where not a.Suspended do a.ClicksRemaining := a.ClicksRemaining - slice; if a.ClicksRemaining <= 0 then DetachToken(a, x + y); else cds := min(cds, a.ClicksRemaining); endif; endfor; if r.ActiveTokenCount = 0 then r.ControlsDuration := false; else r.ClicksDoSomething := cds * actcnt; endif; endlocals; else r.ControlsDuration := false; endif; endlocals; endif; endfor; x := x + y; update mk := MoveTokenList do AttachToken(mk, x); remove mk; endupdate; break : x >= ClicksPerLoop; endloop; LoopNumber := LoopNumber + 1; if LoopNumber >= StartSeconds then LoopNumber := 0; TokenStartInx := 0; endif; for r := ResourceBoxList do r.SetStatsHeight(); endfor; BarChart.Data := null; for a := ActionBoxList where a.NumTokens > 0 do BarChart.Data append _namenumber{a.DataObject.Name, a.CummulativeET / a.NumTokens}; endfor; return RedisplayShapes; ’ĶĶ’’’’ĶĶĶĶķ`$ é% A& ’ĶĶ’’’’ĶĶĶĶ'{for r := ResourceBoxList do r.QueueModelClear(); r.ControlsDuration := false; endfor; locals n float := 0; totalClicks int; do for ps := PathStartList do n := n + ps.Number * PathFactor; endfor; StartSeconds := (1000.0 div n) + 1; totalClicks := StartSeconds * ClicksPerLoop; set_prandom_seed(totalClicks); repeat StartSeconds do üĄQ#Zn‹’ĶĶ’’’’ĶĶĶĶ(Y for p := PathStartList do repeat round(p.Number * PathFactor) do TokenStartList append new TokenStart call SetUp(p.FirstAction, totalClicks); endrepeat; endfor; endrepeat; sort_asc_in_place(TokenStartList, "Time"); endlocals; locals itb := new InfoTextBox; do Shapes append itb; Seconds := new IntInfoTextLine call SetUp("Second = "); itb.Add(Seconds); TokensStarted := new IntInfoTextLine call SetUp("Tokens started = "); itb.Add(TokensStarted); TokensEnded := new IntInfoTextLine call SetUp("Tokens ended = "); itb.Add(TokensEnded); TotalElapsed := 0; ElapsedAvg := new IntInfoTextLine call SetUp("Elapsed time average (msecs) = "); itb.Add(ElapsedAvg); ElapsedMax := new IntInfoTextLine call SetUp("Elapsed time max (msecs) = "); itb.Add(ElapsedMax); endlocals; BarChart := new MetricShape; BarChart.Left := 0; BarChart.Top := 0; BarChart.Title := "Average Action Elapsed Time"; MainHorz.Shapes append BarChart; return RedisplayShapes; ’ĶĶ’’’’ĶĶĶĶź{' Y( ’ĶĶ’’’’ĶĶĶĶē–if notnull LastElement then Shapes append new SimpleDirectConn call SetUp(LastElement, al); LastElement.Next := al; endif; LastElement := al; ’ĶĶ’’’’ĶĶĶĶćfor r := ResourceBoxList where r.DataObject = ut.Resource do r.AddAction(ut, num, bx, above); return r; endfor; locals rb := new ResourceBox call SetUp(ut.Resource); do ResourceBoxList append rb; rb.AddAction(ut, num, bx, above); return rb; endlocals; ’ĶĶ’’’’ĶĶĶĶ)¦for a := al do if notempty(a.SubActions) then st.Shapes append new ActionStripe call SetUp(a, above, num, subno); elseif empty(a.Utils) then NoUtilsCount := NoUtilsCount + 1; else if a is MsgAction then st.Shapes append new ActionMsgBox call SetUp(a, above, num, subno); else st.Shapes append new ActionBox call SetUp(a, above, num, subno); endifü«&č~¤®Pŗ’ĶĶ’’’’ĶĶĶĶ*; endif; endfor; ’ĶĶ’’’’ĶĶĶĶܦ) * ’ĶĶ’’’’ĶĶĶĶŌėMainHorz := new MainStripeFrame; Shapes append MainHorz; locals mainvert := new MainStripeVert; resourcestripe := new HorzStripeSimple; titlebox := new TitleBox call SetUp("Path Performance for: "); firsttime := true; cnt := 0; do MainHorz.Shapes append mainvert; mainvert.Shapes append titlebox; for p := ImpPathList do titlebox.Add(p); locals ps := new HorzStripeSimple; do BuildPath(p.Actions, ps, firsttime, p.Number * PathFactor, 0); mainvert.Shapes append ps; if firsttime then mainvert.Shapes append resourcestripe; firsttime := false; endif; if notempty(ps.Shapes) and notnull p.Number and ps.Shapes [first] is ActionBoxBase -> al then PathStartList append new PathStart call SetUp(al, p.Number); endif; LastElement := null; endlocals; cnt := cnt + 1; endfor; if cnt = 0 then stop "No implementation paths selected"; endif; resourcestripe.Shapes appendlist ResourceBoxList; endlocals; if NoUtilsCount > 0 then log "Somes action not displayed because they had no utilization info"; endif; ’ĶĶ’’’’ĶĶĶĶŃ0’ĶĶ’’’’ĶĶĶĶÅ0’ĶĶ’’’’ĶĶĶĶĆ0’ĶĶ’’’’ĶĶĶĶĄ1000’ĶĶ’’’’ĶĶĶĶŗ1’ĶĶ’’’’ĶĶĶĶø0’ĶĶ’’’’ĶĶĶĶÆMsg := msg; Val := 0; ’ĶĶ’’’’ĶĶĶĶ„Msg := msg; Val := 0; ’ĶĶ’’’’ĶĶĶĶ™ Msg := msg; ’ĶĶ’’’’ĶĶĶ͐5.0’ĶĶ’’’’ĶĶĶ͊Shapes append itl; ’ĶĶ’’’’ĶĶĶĶ~“if NamesCount = 1 then Names := NewText; MainObj.Name := str_after(NewText, ": "); return RedisplayShapes; endif; return ErrUserError; ’ĶĶ’’’’ĶĶĶĶz‡if NamesCount = 0 then MainObj := n; else Names := Names & ", "; endif; Names := Names & n.Name; NamesCount := NamesCount + 1; ’ĶĶ’’’’ĶĶĶĶv>Names := pr; NamesCount := 0; DisplayControl := flag(eSmall); üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü?ʹ,3“·’ĶĶ’’’’ĶĶĶĶkpif isnull DataObject then return ErrNoDataObject; endif; DataObject.Name := NewText; return RedisplayShapes; ’ĶĶ’’’’ĶĶĶĶbpif isnull DataObject then return ErrNoDataObject; endif; DataObject.Name := NewText; return RedisplayShapes; ’ĶĶ’’’’ĶĶĶĶLUempty(Utils) or count(for u := Utils where u.Resource.Category <> eFixed endfor) = 1 ’ĶĶ’’’’ĶĶĶĶJfalse’ĶĶ’’’’ĶĶĶĶA0’ĶĶ’’’’ĶĶĶĶ?0’ĶĶ’’’’ĶĶĶĶ=0’ĶĶ’’’’ĶĶĶĶ11000’ĶĶ’’’’ĶĶĶĶ/1’ĶĶ’’’’ĶĶĶĶ-eFixed’ĶĶ’’’’ĶĶĶĶ1’ĶĶ’’’’ĶĶĶĶ notnull Name ’ĶĶ’’’’ĶĶĶĶ  Name := n; ’ĶĶ’’’’ĶĶĶĶ return Name; ž’ĶĶ<=$Performance Model  S Ė €G'  Š f ē č é ź ė ģ 2008v2 ę ZFor more information see: www.WeaverBird.org’Ķ͆?NamedObj€'       + ’ĶĶŹ?System€' ,      - ’ĶĶ£9?UtilResource€' .  :  ;  Ų ’Ķ͵ N?ProcAction€' O  P  Q  / ’ĶĶš P?MsgAction€' Q  R  S  0 ’ĶĶW U? MainStripeFrame€' V  T Ņ U  1 ’ĶĶØ W?MainStripeVert€' X  V Ó W  2 ’ĶĶ÷ Y?"HorzStripeSimple€' Z  X Ō Y  3 ’ĶĶJ [?BoxWithName€' \  ]  ^  4 ’ĶĶOd?StripeWithName€' e  f  g  5 ’ĶĶZm?TitleBox€ ' n  o Õ p  6 ’ĶĶI„?InfoTextBox€"' …  † Ö ‡  7 ’ĶĶŒ?InfoTextLine€#'   Ž    8 ’ĶĶ’’? HeadingTextLine€$' “  ” × •  9 ’ĶĶs›?BlankTextLine€%' œ  Z Ų [  : ’ĶĶĄ? IntInfoTextLine€&' ž  Ÿ Ł    ; ’Ķͧ?$FloatInfoTextLine€'' Ø  © Ś Ŗ  < ’Ķͳ?PathPerfDiag€(' “  µ Ż ¶  = ’ĶĶ’’’’ĶĶĶĶ„  ‚  A ƒ ’ĶĶg ? Token€)' >      Ü ’ĶĶ’’’’ĶĶĶĶŚ'' … ’ĶĶ’’’’ĶĶĶ͈  †  A ‡ ’ĶĶī?TokenStart€*' ?      Ž ’ĶĶ’’’’ĶĶĶĶŅ' AHBHB’ĶĶ’’’’ĶĶĶĶÓ'ČBHBHB’ĶĶ5?PathStart€+' @      ą ’ĶĶ’’’’ĶĶĶĶŌ' ‰  A A’ĶĶ` =?ActionBox€-' >  \ Ž ]  A üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü>LźŅ2ĆO’ĶĶ„ ??ActionMsgBox€.' @  ^ ß _  B ’ĶĶš A?ActionStripe€/' B  C ą D ³  C ’ĶĶ` M?ResourceBox€0' N  O Ū P ³  ä ’ĶĶ®?ResourceConn€1' ‚  ƒ į „  D ’ĶĶŗ‹?"SimpleDirectConn€2' Œ   ā Ž  E ’ĶĶ­”?MetricShape€3' •  – Ü —  F ’ĶĶn›? RandomnessChart€4' œ    ž  G ’ĶĶ+«?VertBarShape€5' ¬  ­ ć ®  H ’ĶĶö²?"StripeVertFigure€6' ³  ` ä a  I ’ĶĶI “? LayerRectFigure€7' µ  ¶ å ·  J ’ĶĶŅ ¹?ServerDBFigure€8' ŗ  » ę ¼  K ’ĶĶY ¾?RoundedFigure€9' æ  Ą ē Į  L ’ĶĶŽ Ć?DiskFigure€:' Ä  Å č Ę  M ’ĶĶ] Č?LineFigure€;' É  b é c  N ’ĶĶŚ Ķ? Guide€<' Ī  d  e  O ’ĶĶ ŃR"Performance Path Ż ’ĶĶM ŅR"Randomness Chart ź ’ĶĶ’’’’ĶĶĶĶŻ('2Path Performance Diagram Š ’ĶĶ’’’’ĶĶĶĶŽ-'Action ‹ ’ĶĶ’’’’ĶĶĶ͌„ BpB’ĶĶ’’’’ĶĶĶĶ†   BpB’ĶĶ’’’’ĶĶĶĶ   @ @\BHB Ž ’ĶĶ’’’’ĶĶĶĶß.'Action  ’ĶĶ’’’’ĶĶĶĶ‘†   A A’ĶĶ’’’’ĶĶĶĶą/'.Action With SubActions ’  A A A A’ĶĶ’’’’ĶĶĶĶ•†   A “ ”  @ @’ĶĶ’’’’ĶĶĶĶ—  ČA @€æ A – ’ĶĶ’’’’ĶĶĶĶŪ0'IT Resource ˜ ’ĶĶ’’’’ĶĶĶĶ™„ B–B’ĶĶ’’’’ĶĶĶ͚†  ŒB–B’ĶĶ’’’’ĶĶĶĶgX“C A B AOK’ĶĶ’’’’ĶĶĶĶ† util ō 4B ›  A œ ’ĶĶ’’’’ĶĶĶĶhX“CHB B ACancel’ĶĶ’’’’ĶĶĶĶž†  4B A AHB’ĶĶ’’’’ĶĶĶĶiV A A CCHC6Select Implementation PathImpPathList’ĶĶ’’’’ĶĶĶ͟  ųApA B A 100%’ĶĶ’’’’ĶĶĶĶ”   B\BHB   ’ĶĶ’’’’ĶĶĶĶjU A A CC k ’ĶĶ’’’’ĶĶĶĶ£‡ ¢  ī pApA A’ĶĶ’’’’ĶĶĶĶlY Number or Slots Slots’ĶĶ’’’’ĶĶĶĶ„… ¤ @ČAČA@’ĶĶ’’’’ĶĶĶĶmY"Number or ThingsThings’ĶĶ’’’’ĶĶĶĶnY$Use Pseudo RandomIsPseudo’ĶĶ’’’’ĶĶĶͧ… ¦  @ąAąA @’ĶĶ’’’’ĶĶĶĶoY&Pseudo Random SeedPseudoSeed’ĶĶ’’’’ĶĶĶĶpU ApC CC q ’ĶĶ’’’’ĶĶĶĶŖ‹ Ø  © ’ĶĶ’’’’ĶĶĶͬ… «  A°A A°A’ĶĶ’’’’ĶĶĶĶ®… ­  A€A A€A’ĶĶ’’’’ĶĶĶĶrY Number of UsersNumberOfUsers’ĶĶ’’’’ĶĶĶĶį1'Uses Resource õ üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü͆½ŒŌlÆ’ĶĶ’’’’ĶĶĶĶsY6Number of Paths MultiplierPathFactor’ĶĶ’’’’ĶĶĶĶā2'2Miscellaneous connection õ ’ĶĶ’’’’ĶĶĶĶÕ ' t ’ĶĶ’’’’ĶĶĶĶÜ3' Æ ČC ²  ’ĶĶ’’’’ĶĶĶĶvƒ u HC B’ĶĶ’’’’ĶĶĶͱ  HC Ā€æ B ° ’ĶĶ’’’’ĶĶĶĶxƒ w HC C’ĶĶ’’’’ĶĶĶĶz   A y ’ĶĶ’’’’ĶĶĶĶź4'"Randomness Chart ³ ’ĶĶ’’’’ĶĶĶĶć5' “ HCČC ·  ’ĶĶ’’’’ĶĶĶͶ   ĀHC B µ ’ĶĶ’’’’ĶĶĶĶÖ"' @’ĶĶ’’’’ĶĶĶĶä6'HBšAŒB’ĶĶ’’’’ĶĶĶĶ×$' { ’ĶĶ’’’’ĶĶĶĶē9' ø ’ĶĶ’’’’ĶĶĶĶ~  |  A } ’ĶĶ’’’’ĶĶĶ͹† ń  B B @ @’ĶĶ’’’’ĶĶĶĶŲ%'  ’ĶĶ’’’’ĶĶĶĶ»  @ A€æ ŗ ’ĶĶ’’’’ĶĶĶĶå7' ¼ ’ĶĶ’’’’ĶĶĶͽ† ķ HC B’ĶĶ’’’’ĶĶĶĶæ  @ ADC A ¾ ’ĶĶ’’’’ĶĶĶĶę8' Ą ’ĶĶ’’’’ĶĶĶĶĮ† ń  B B @ @’ĶĶ’’’’ĶĶĶĶƐ  @˜B B Ā ’ĶĶ’’’’ĶĶĶĶĈ š  BŖB A @’ĶĶ’’’’ĶĶĶĶņ ļ šA\B AšA’ĶĶ’’’’ĶĶĶĶĘˆ š  B\B A @’ĶĶ’’’’ĶĶĶĶĒ… š šA\BšAŖB’ĶĶ’’’’ĶĶĶĶČ… š HB\BHBŖB’ĶĶ’’’’ĶĶĶĶ€ƒČB A’ĶĶ’’’’ĶĶĶĶč:' É DB’ĶĶ’’’’ĶĶĶĶŁ&'  ’ĶĶ’’’’ĶĶĶĶŹ„ AšA’ĶĶ’’’’ĶĶĶĶĖˆ š  AČA A @’ĶĶ’’’’ĶĶĶĶ̆ ļ  @ A A’ĶĶ’’’’ĶĶĶĶĶˆ š  A @ A @’ĶĶ’’’’ĶĶĶĶĪ… š  @ČA’ĶĶ’’’’ĶĶĶĶĻ… š  A @ AČA’ĶĶ’’’’ĶĶĶĶѐ   Āą@ČB A Š ’ĶĶ’’’’ĶĶĶĶé;'  ’ĶĶ’’’’ĶĶĶĶÉUŹ Ė Ģ Ķ Ī Ļ Ń ’ĶĶ’’’’ĶĶĶĶĄUĮ Ć Ä Å Ę Ē Č ’ĶĶ’’’’ĶĶĶͼU½ æ ’ĶĶ’’’’ĶĶĶĶøU¹ » ’ĶĶ’’’’ĶĶĶĶ·Zó ’ĶĶ’’’’ĶĶĶĶ“U¶ ’ĶĶ’’’’ĶĶĶͳRj g h ’ĶĶ’’’’ĶĶĶͲZō ’ĶĶ’’’’ĶĶĶĶÆU± ’ĶĶ’’’’ĶĶĶĶ©cA @AąA°AąA°A @’ĶĶ’’’’ĶĶĶ͘U ™ š  ž Ÿ ” £ „ § Ŗ ¬ ® ’ĶĶ’’’’ĶĶĶĶ’U• — ’ĶĶ’’’’ĶĶĶ͐U‘ ’ĶĶ’’’’ĶĶĶĶ‹UŒ   ’ĶĶ’’’’ĶĶĶ͊Ri p g h ’ĶĶ’’’’ĶĶĶĶ…Uˆ ’ĶĶ’’’’ĶĶĶ́U„ ’ĶĶ’’’’ĶĶĶĶU€ ’ĶĶ’’’’ĶĶĶĶ{U~ ’ĶĶ’’’’ĶĶĶĶtUv x z ’ĶĶ’’’’ĶĶĶĶqSr s ’ĶĶ’’’’ĶĶĶĶkSl m n o ’ĶĶ’’’’ĶĶĶĶfA’ĶĶ’’’’ĶĶĶĶeD’ĶĶ’’’’ĶĶĶĶdC’ĶĶ’’’’ĶĶĶĶcD’ĶĶ’’’’ĶĶĶĶbC’ĶĶ’’’’ĶĶĶĶaD’ĶĶ’’’’ĶĶĶĶ`C’ĶĶ’’’’ĶĶĶĶ_D’ĶĶ’’’’ĶĶĶĶ^C’ĶĶ’’’’ĶĶĶĶ]D’ĶĶ’’’’ĶĶĶĶ\C’ĶĶ’’’’ĶĶĶĶ[D’ĶĶ’’’’ĶĶĶĶZC’ĶĶ’’’’ĶĶĶĶYD’ĶĶ’’’’ĶĶĶĶXC’ĶĶ’’’’ĶĶĶĶWDüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü¹ØPdßk’ĶĶ’’’’ĶĶĶĶVC’ĶĶ’’’’ĶĶĶĶUD’ĶĶ’’’’ĶĶĶĶTC’ĶĶ’’’’ĶĶĶĶSD’ĶĶ’’’’ĶĶĶĶRC’ĶĶ’’’’ĶĶĶĶQD’ĶĶ’’’’ĶĶĶĶPC’ĶĶ’’’’ĶĶĶĶO@’ĶĶ’’’’ĶĶĶĶN@’ĶĶ’’’’ĶĶĶĶM@’ĶĶ’’’’ĶĶĶĶL@’ĶĶ’’’’ĶĶĶĶK@’ĶĶ’’’’ĶĶĶĶJ@’ĶĶ’’’’ĶĶĶĶI@’ĶĶ’’’’ĶĶĶĶH@’ĶĶ’’’’ĶĶĶĶG@’ĶĶ’’’’ĶĶĶĶF@’ĶĶ’’’’ĶĶĶĶE@’ĶĶ’’’’ĶĶĶĶD@’ĶĶ’’’’ĶĶĶĶC@’ĶĶ’’’’ĶĶĶĶB@’ĶĶ’’’’ĶĶĶĶA@’ĶĶ’’’’ĶĶĶĶ@B’ĶĶ’’’’ĶĶĶĶ?B’ĶĶ’’’’ĶĶĶĶ>B’ĶĶ’’’’ĶĶĶĶ=@’ĶĶ’’’’ĶĶĶĶ<@’ĶĶ’’’’ĶĶĶĶ;@’ĶĶ’’’’ĶĶĶĶ:@’ĶĶ’’’’ĶĶĶĶ9@’ĶĶ’’’’ĶĶĶĶ8@’ĶĶ’’’’ĶĶĶĶ7@’ĶĶ’’’’ĶĶĶĶ6@’ĶĶ’’’’ĶĶĶĶ5@’ĶĶ’’’’ĶĶĶĶ4@’ĶĶ’’’’ĶĶĶĶ3@’ĶĶ’’’’ĶĶĶĶ2@’ĶĶ’’’’ĶĶĶĶ1@’ĶĶ’’’’ĶĶĶĶ0@’ĶĶ’’’’ĶĶĶĶ/@’ĶĶ’’’’ĶĶĶĶ.B’ĶĶ’’’’ĶĶĶĶ-@’ĶĶ’’’’ĶĶĶĶ,B’ĶĶ’’’’ĶĶĶĶ+@’ĶĶƒ źQg h i j p ’ĶĶ’’’’ĶĶĶĶŠ = shape.Title’ĶĶ’’’’ĶĶĶĶĀ = shape.Title’ĶĶ’’’’ĶĶĶ; = shape.Title’ĶĶ’’’’ĶĶĶĶŗ = shape.Title’ĶĶ’’’’ĶĶĶ͵ = shape.Title’ĶĶ’’’’ĶĶĶͰ = shape.Title’ĶĶ’’’’ĶĶĶĶ­= flag(eQueued)’ĶĶ’’’’ĶĶĶĶ«= flag(eQueued)’ĶĶ’’’’ĶĶĶĶØ= flag(eQueued)’ĶĶ’’’’ĶĶĶͦ= flag(eTimesliced)’ĶĶ’’’’ĶĶĶͤ= flag(eTimesliced)’ĶĶ’’’’ĶĶĶĶ¢= flag(eTimesliced)’ĶĶ’’’’ĶĶĶĶ  = shape.Title’ĶĶ’’’’ĶĶĶ͜= shape.StatsHeight’ĶĶ’’’’ĶĶĶĶ›= shape.StatsY’ĶĶ’’’’ĶĶĶĶ–= shape.DataObject.Name’ĶĶ’’’’ĶĶĶĶ”=shape.GetHeight() - 10.0’ĶĶ’’’’ĶĶĶĶ“=shape.GetWidth() - 20.0’ĶĶ’’’’ĶĶĶĶŽ = shape.Title’ĶĶ’’’’ĶĶĶ͉1= if count(Shapes) > 3 then 50.0 else 100.0 endif’ĶĶ’’’’ĶĶĶ͇= shape.Msg & str(shape.Val)’ĶĶ’’’’ĶĶĶ͆= shape.Margin’ĶĶ’’’’ĶĶĶ̓= shape.Msg & str(shape.Val)’ĶĶ’’’’ĶĶĶĶ‚= shape.Margin’ĶĶ’’’’ĶĶĶĶ} = shape.Msg’ĶĶ’’’’ĶĶĶĶ|= shape.Margin’ĶĶ’’’’ĶĶĶĶy = shape.Names’ĶĶ’’’’ĶĶĶĶw = flag(eBig)’ĶĶ’’’’ĶĶĶĶu= flag(eSmall)žżŁ”Õ.7ImportĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢ’ĶĶƒ=$Performance Model  S Ė €G'  Š f ē č é ź ė ģ 2008v2 ė ę ZFor more information see: www.WeaverBird.org’ĶĶ’’’’<ėžüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüĻæ Šˆ¤¹,ĶĶĶ1Źv ’’’’ĶĶĶĶ’’’’ĶĶĶĶ3>’ĶĶ’’’’ĶĶĶĶv'Path Test  a ’ĶĶ’’’’ĶĶĶĶ 'Simple App€?  ’ĶĶ’’’’ĶĶĶĶ'$Workstation input  ’ĶĶ’’’’ĶĶĶĶ' m  @ @  ’ĶĶ’’’’ĶĶĶĶ'2Internal network message  ’ĶĶ’’’’ĶĶĶĶ' g HC  ’ĶĶ’’’’ĶĶĶĶ 'RPC in  ’ĶĶ’’’’ĶĶĶĶ ' i @  ’ĶĶ’’’’ĶĶĶĶ ' k ĶĢĢ=ĶĢĢ=  ’ĶĶ’’’’ĶĶĶĶ '8Data processing application  ’ĶĶ’’’’ĶĶĶĶ' i @ @  ’ĶĶ’’’’ĶĶĶĶ' k €?ĶĢĢ=  ’ĶĶ’’’’ĶĶĶĶ'Database  ’ĶĶ’’’’ĶĶĶĶ' i  @€?  ’ĶĶ’’’’ĶĶĶĶ' k ĶĢĢ=ČB@  ’ĶĶ’’’’ĶĶĶĶ'8Data processing application  ’ĶĶ’’’’ĶĶĶĶ' i €?  ’ĶĶ’’’’ĶĶĶĶ'RPC out  ’ĶĶ’’’’ĶĶĶĶ' i €?  ’ĶĶ’’’’ĶĶĶĶ'2Internal network message  ’ĶĶ’’’’ĶĶĶĶ' g śD  ’ĶĶ’’’’ĶĶĶĶ'&Workstation output  ’ĶĶ’’’’ĶĶĶĶ' m €?  ’ĶĶ’’’’ĶĶĶĶ@'BWeb App with Transaction Monitor€? ! ’ĶĶ’’’’ĶĶĶĶ#'(External message in " ’ĶĶ’’’’ĶĶĶĶ$' c ČB # ’ĶĶ’’’’ĶĶĶĶ&'Web Server App % ( ’ĶĶ’’’’ĶĶĶĶ'' e  @ A & ’ĶĶ’’’’ĶĶĶĶ*'"Inner message in ) ’ĶĶ’’’’ĶĶĶĶ+' g HC * ’ĶĶ’’’’ĶĶĶĶ-'Middleware , 0 ’ĶĶ’’’’ĶĶĶĶ.' k ? A - ’ĶĶ’’’’ĶĶĶĶ/' i  @ @ - ’ĶĶ’’’’ĶĶĶĶ2' Data processing 1 5 ’ĶĶ’’’’ĶĶĶĶ3' k €? @ 2 ’ĶĶ’’’’ĶĶĶĶ4' i €?€? 2 ’ĶĶ’’’’ĶĶĶĶ7'Database 6 ’ĶĶ’’’’ĶĶĶĶ8' k @ A 7 ’ĶĶ’’’’ĶĶĶĶ9' i  @€? 7 ’ĶĶ’’’’ĶĶĶĶ;'$Inner message out : ’ĶĶ’’’’ĶĶĶĶ<' g zD ; ’ĶĶ’’’’ĶĶĶĶ>'*External message out = ’ĶĶ’’’’ĶĶĶĶ?' c `źF > ’ĶĶ’’’’ĶĶĶĶR'$App Server and DBpA A ’ĶĶ’’’’ĶĶĶĶC'App B ’ĶĶ’’’’ĶĶĶĶD' o  A @ C ’ĶĶ’’’’ĶĶĶĶE' q  AČB C ’ĶĶ’’’’ĶĶĶĶG'(DB Connector Client F ’ĶĶ’’’’ĶĶĶĶH' o  @ G ’ĶĶ’’’’ĶĶĶĶI' q @ G ’ĶĶ’’’’ĶĶĶĶK'(DB Connector Server J ’ĶĶ’’’’ĶĶĶĶL' s  @ K ’ĶĶ’’’’ĶĶĶĶM' u @ K ’ĶĶ’’’’ĶĶĶĶO'Database N ’ĶĶ’’’’ĶĶĶĶP' s  A O ’ĶĶ’’’’ĶĶĶĶQ' u HC O ’ĶĶ’’’’ĶĶĶĶ`'One ServerpA S ’ĶĶ’’’’ĶĶĶĶU'App T ’ĶĶ’’’’ĶĶĶĶV' s  A @ U ’ĶĶ’’’’ĶĶĶĶW' u  AČB U ’ĶĶ’’’’ĶĶĶĶY'DB Connector X üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüŲ93bŠ Ļ1’ĶĶ’’’’ĶĶĶĶZ' s @ Y ’ĶĶ’’’’ĶĶĶĶ[' u @ Y ’ĶĶ’’’’ĶĶĶĶ]'Database \ ’ĶĶ’’’’ĶĶĶĶ^' s  A ] ’ĶĶ’’’’ĶĶĶĶ_' u HC ] ’ĶĶ’’’’ĶĶĶĶc'"External network$tI b ’ĶĶ’’’’ĶĶĶĶe',Web server processingČB d ’ĶĶ’’’’ĶĶĶĶg'Inner network$tI f ’ĶĶ’’’’ĶĶĶĶi'6Processing App & Db serverČB h ’ĶĶ’’’’ĶĶĶĶk'.Memory App & Db serverzD j ’ĶĶ’’’’ĶĶĶĶm',Workstation processorČB l ’ĶĶ’’’’ĶĶĶĶo'6Processing App Only Server ČB n ’ĶĶ’’’’ĶĶĶĶq'.Memory App Only Server śC p ’ĶĶ’’’’ĶĶĶĶs'4Processing DB only ServerČC r ’ĶĶ’’’’ĶĶĶĶu',Memory DB Only ServerzD t ’ĶĶ’’’’ĶĶĶĶt@'M Q W [ _ ’ĶĶ’’’’ĶĶĶĶr@'L P V Z ^ ’ĶĶ’’’’ĶĶĶĶp@'E I ’ĶĶ’’’’ĶĶĶĶn@'D H ’ĶĶ’’’’ĶĶĶĶl@'  ’ĶĶ’’’’ĶĶĶĶj@'    . 3 8 ’ĶĶ’’’’ĶĶĶĶh@'      / 4 9 ’ĶĶ’’’’ĶĶĶĶf@'  + < ’ĶĶ’’’’ĶĶĶĶd@'' ’ĶĶ’’’’ĶĶĶĶb@'$ ? ’ĶĶ’’’’ĶĶĶĶa?' c e g i k m o q s u ’ĶĶ’’’’ĶĶĶĶ\@'^ _ ’ĶĶ’’’’ĶĶĶĶX@'Z [ ’ĶĶ’’’’ĶĶĶĶT@'V W ’ĶĶ’’’’ĶĶĶĶSA'U Y ] ’ĶĶ’’’’ĶĶĶĶN@'P Q ’ĶĶ’’’’ĶĶĶĶJ@'L M ’ĶĶ’’’’ĶĶĶĶF@'H I ’ĶĶ’’’’ĶĶĶĶB@'D E ’ĶĶ’’’’ĶĶĶĶAA'C G K O ’ĶĶ’’’’ĶĶĶĶ=@'? ’ĶĶ’’’’ĶĶĶĶ:@'< ’ĶĶ’’’’ĶĶĶĶ6@'8 9 ’ĶĶ’’’’ĶĶĶĶ5A'7 ’ĶĶ’’’’ĶĶĶĶ1@'3 4 ’ĶĶ’’’’ĶĶĶĶ0A'2 ’ĶĶ’’’’ĶĶĶĶ,@'. / ’ĶĶ’’’’ĶĶĶĶ)@'+ ’ĶĶ’’’’ĶĶĶĶ(A'* - ; ’ĶĶ’’’’ĶĶĶĶ%@'' ’ĶĶ’’’’ĶĶĶĶ"@'$ ’ĶĶ’’’’ĶĶĶĶ!A'# & > ’ĶĶ’’’’ĶĶĶĶ@' ’ĶĶ’’’’ĶĶĶĶ@' ’ĶĶ’’’’ĶĶĶĶ@' ’ĶĶ’’’’ĶĶĶĶ@' ’ĶĶ’’’’ĶĶĶĶ@'  ’ĶĶ’’’’ĶĶĶĶ @'  ’ĶĶ’’’’ĶĶĶĶ@'   ’ĶĶ’’’’ĶĶĶĶ@' ’ĶĶ’’’’ĶĶĶĶ@' ’ĶĶ’’’’ĶĶĶĶA'          ’ĶĶ’’’’ĶĶĶĶ='  @ R ` žżŁ”š7ImportĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢ’ĶͶ'$Workstation input  x ’ĶĶ:'2Internal network message  y ’ĶĶĢ 'RPC in  z ’ĶĶu '8Data processing application  { ’ĶĶH'Database  | ’ĶĶõ'8Data processing application  } ’ĶĶ'RPC out  ~ üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüa+?¼—}“,ĶĶĶ2Ó  ’’’’ĶĶĶĶ’’’’ĶĶĶĶ3>’ĶĶ’’’’ĶĶĶĶĆ>Performance Modelling Tutorial      <For WeaverBird version 2008v2JCopyright (c) 2008, Polyphony IT Ltd’ĶĶ’’’’ĶĶĶĶ<'’ĶĶ’’’’ĶĶĶͶIntroduction  ’ĶĶ’’’’ĶĶĶͶ,Modelling Performance   ’ĶĶ’’’’ĶĶĶͶModelRand*Modelling Randomness  ’ĶĶ’’’’ĶĶĶĶ ¶2Simple Performance Model  ’ĶĶ’’’’ĶĶĶĶ ¶4Queuing Performance Model  ’ĶĶ’’’’ĶĶĶĶ ¶Complexities  ’ĶĶ’’’’ĶĶĶͶ Perf6Some Issues and Approaches  ’ĶĶ’’’’ĶĶĶͶchange0Changing the Model Data  ’ĶĶ’’’’ĶĶĶĶBŗmultappsone:Multiple Application Servers  ’ĶĶ’’’’ĶĶĶĶ>i   A A’ĶĶ’’’’ĶĶĶĶ=6' AšA  ŒB’ĶĶ’’’’ĶĶĶĶ7'  &Presentation Layer’ĶĶ’’’’ĶĶĶ͆ ķ HC B’ĶĶ’’’’ĶĶĶ͐  @ ADC A  ’ĶĶ’’’’ĶĶĶĶ<'   A A A’ĶĶ’’’’ĶĶĶĶ 8'   App & DB Server’ĶĶ’’’’ĶĶĶĶ!† ń  B B @ @’ĶĶ’’’’ĶĶĶĶ"  @˜B B  ’ĶĶ’’’’ĶĶĶĶ#ˆ š  BŖB A @’ĶĶ’’’’ĶĶĶĶ$† ļ šA\B AšA’ĶĶ’’’’ĶĶĶĶ%ˆ š  B\B A @’ĶĶ’’’’ĶĶĶĶ&… š šA\BšAŖB’ĶĶ’’’’ĶĶĶĶ'… š HB\BHBŖB’ĶĶ’’’’ĶĶĶĶ*8' (  App & DB Server’ĶĶ’’’’ĶĶĶĶ+† ń  B B @ @’ĶĶ’’’’ĶĶĶĶ,  @˜B B ) ’ĶĶ’’’’ĶĶĶĶ-ˆ š  BŖB A @’ĶĶ’’’’ĶĶĶĶ.† ļ šA\B AšA’ĶĶ’’’’ĶĶĶĶ/ˆ š  B\B A @’ĶĶ’’’’ĶĶĶĶ0… š šA\BšAŖB’ĶĶ’’’’ĶĶĶĶ1… š HB\BHBŖB’ĶĶ’’’’ĶĶĶĶ48' 2  App & DB Server’ĶĶ’’’’ĶĶĶĶ5† ń  B B @ @’ĶĶ’’’’ĶĶĶĶ6  @˜B B 3 ’ĶĶ’’’’ĶĶĶĶ7ˆ š  BŖB A @’ĶĶ’’’’ĶĶĶĶ8† ļ šA\B AšA’ĶĶ’’’’ĶĶĶĶ9ˆ š  B\B A @’ĶĶ’’’’ĶĶĶĶ:… š šA\BšAŖB’ĶĶ’’’’ĶĶĶĶ;… š HB\BHBŖB’ĶĶ’’’’ĶĶĶĶ?;'      ’ĶĶ’’’’ĶĶĶĶ@;'     * ’ĶĶ’’’’ĶĶĶĶA;'     4 ’ĶĶ’’’’ĶĶĶĶoŗmultappstwo:Multiple Application Servers C ’ĶĶ’’’’ĶĶĶĶhi D  A A’ĶĶ’’’’ĶĶĶĶg6'›CšA E ŒB’ĶĶ’’’’ĶĶĶĶH7' F &Presentation Layer’ĶĶ’’’’ĶĶĶĶI† ķ HC B’ĶĶ’’’’ĶĶĶĶJ  @ ADC A G ’ĶĶ’’’’ĶĶĶĶ\' L  A A A’ĶĶ’’’’ĶĶĶĶO9' M App Server’ĶĶ’’’’ĶĶĶĶP† ń  B B @ @’ĶĶ’’’’ĶĶĶĶQ  @ A€æ N ’ĶĶ’’’’ĶĶĶĶT9' R App Serverüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüé±ŃrO’CĘ’ĶĶ’’’’ĶĶĶĶU† ń  B B @ @’ĶĶ’’’’ĶĶĶĶV  @ A€æ S ’ĶĶ’’’’ĶĶĶĶY9' W App Server’ĶĶ’’’’ĶĶĶĶZ† ń  B B @ @’ĶĶ’’’’ĶĶĶĶ[  @ A€æ X ’ĶĶ’’’’ĶĶĶĶ_:' ] Data Layer’ĶĶ’’’’ĶĶĶĶ`„ AšA’ĶĶ’’’’ĶĶĶĶaˆ š  AČA A @’ĶĶ’’’’ĶĶĶĶb† ļ  @ A A’ĶĶ’’’’ĶĶĶĶcˆ š  A @ A @’ĶĶ’’’’ĶĶĶĶd… š  @ČA’ĶĶ’’’’ĶĶĶĶe… š  A @ AČA’ĶĶ’’’’ĶĶĶĶf   Āą@ČB A ^ ’ĶĶ’’’’ĶĶĶĶi;'   H  O ’ĶĶ’’’’ĶĶĶĶj;'   H  T ’ĶĶ’’’’ĶĶĶĶk;'   H  Y ’ĶĶ’’’’ĶĶĶĶl;'   O  _ ’ĶĶ’’’’ĶĶĶĶm;'   T  _ ’ĶĶ’’’’ĶĶĶĶn;'   Y  _ ’ĶĶ’’’’ĶĶĶĶŗpathmod.Performance Path Model p ’ĶĶ’’’’ĶĶĶĶs-'Action q HBHB Workstation App’ĶĶ’’’’ĶĶĶĶt„ BpB’ĶĶ’’’’ĶĶĶĶu†   BpB’ĶĶ’’’’ĶĶĶĶv   @ @\BHB r ’ĶĶ’’’’ĶĶĶĶx.'Action w  CŒB’ĶĶ’’’’ĶĶĶĶy†   A A’ĶĶ’’’’ĶĶĶĶ|-'Action z RCHBMiddleware’ĶĶ’’’’ĶĶĶĶ}„ BpB’ĶĶ’’’’ĶĶĶĶ~†   BpB’ĶĶ’’’’ĶĶĶ͐   @ @\BHB { ’ĶĶ’’’’ĶĶĶĶ‚-'Action € –CHB(Data Processing App’ĶĶ’’’’ĶĶĶ̓„ BpB’ĶĶ’’’’ĶĶĶĶ„†   BpB’ĶĶ’’’’ĶĶĶĶ…   @ @\BHB  ’ĶĶ’’’’ĶĶĶ͈-'Action † ĆCHBDatabase’ĶĶ’’’’ĶĶĶ͉„ BpB’ĶĶ’’’’ĶĶĶ͊†   BpB’ĶĶ’’’’ĶĶĶĶ‹   @ @\BHB ‡ ’ĶĶ’’’’ĶĶĶĶŽ-'Action Œ šCHB(Data Processing App’ĶĶ’’’’ĶĶĶĶ„ BpB’ĶĶ’’’’ĶĶĶ͐†   BpB’ĶĶ’’’’ĶĶĶĶ‘   @ @\BHB  ’ĶĶ’’’’ĶĶĶĶ”-'Action ’ €DHBMiddleware’ĶĶ’’’’ĶĶĶĶ•„ BpB’ĶĶ’’’’ĶĶĶĶ–†   BpB’ĶĶ’’’’ĶĶĶĶ—   @ @\BHB “ ’ĶĶ’’’’ĶĶĶĶ™.'Action ˜ %DŒB’ĶĶ’’’’ĶĶĶ͚†   A A’ĶĶ’’’’ĶĶĶĶ-'Action › €6DHB Workstation App’ĶĶ’’’’ĶĶĶĶž„ BpB’ĶĶ’’’’ĶĶĶ͟†   BpB’ĶĶ’’’’ĶĶĶĶ    @ @\BHB œ ’ĶĶ’’’’ĶĶĶͬ0'IT Resource ” 1C4CB°@,Workstation Processor’ĶĶ’’’’ĶĶĶĶ­„ B–B’ĶĶ’’’’ĶĶĶĶ®†  ŒB–B’ĶĶ’’’’ĶĶĶĶÆ† util ō 4B ¢  A £ ’ĶĶ’’’’ĶĶĶͰ†  4B A AHB’ĶĶ’’’’ĶĶĶͱ  ųApA B A 100%’ĶĶ’’’’ĶĶĶͲ   B\BHB ¤ üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüœģ,‘ń"% ’ĶĶ’’’’ĶĶĶͳ‡ „  ī pApA A’ĶĶ’’’’ĶĶĶĶ“… ¦ @ČAČA@’ĶĶ’’’’ĶĶĶ͵… §  @ąAąA @’ĶĶ’’’’ĶĶĶͶ‹ Ø  © ’ĶĶ’’’’ĶĶĶĶ·… Ŗ  A°A A°A’ĶĶ’’’’ĶĶĶĶø… «  A€A A€A’ĶĶ’’’’ĶĶĶĶÄ0'IT Resource ¹ 2€¬C4CˆB@Network’ĶĶ’’’’ĶĶĶĶń B–B’ĶĶ’’’’ĶĶĶĶʆ  ŒB–B’ĶĶ’’’’ĶĶĶĶdž util ō 4B ŗ  A » ’ĶĶ’’’’ĶĶĶĶȆ  4B A AHB’ĶĶ’’’’ĶĶĶĶɐ  ųApA B A 100%’ĶĶ’’’’ĶĶĶĶŹ   B\BHB ¼ ’ĶĶ’’’’ĶĶĶ͎ ½  ī pApA A’ĶĶ’’’’ĶĶĶĶĢ… ¾ @ČAČA@’ĶĶ’’’’ĶĶĶĶĶ… æ  @ąAąA @’ĶĶ’’’’ĶĶĶĶĪ‹ Ą  Į ’ĶĶ’’’’ĶĶĶĶĻ… Ā  A°A A°A’ĶĶ’’’’ĶĶĶĶŠ… Ć  A€A A€A’ĶĶ’’’’ĶĶĶĶÜ0'IT Resource Ń 1€ŁC4CNB”A$Server Processing’ĶĶ’’’’ĶĶĶĶŻ„ B–B’ĶĶ’’’’ĶĶĶĶŽ†  ŒB–B’ĶĶ’’’’ĶĶĶĶ߆ util ō 4B Ņ  A Ó ’ĶĶ’’’’ĶĶĶĶą†  4B A AHB’ĶĶ’’’’ĶĶĶĶᐠ ųApA B A 100%’ĶĶ’’’’ĶĶĶĶ␠  B\BHB Ō ’ĶĶ’’’’ĶĶĶĶ㇠Õ  ī pApA A’ĶĶ’’’’ĶĶĶĶä… Ö @ČAČA@’ĶĶ’’’’ĶĶĶĶå… ×  @ąAąA @’ĶĶ’’’’ĶĶĶĶę‹ Ų  Ł ’ĶĶ’’’’ĶĶĶĶē… Ś  A°A A°A’ĶĶ’’’’ĶĶĶĶč… Ū  A€A A€A’ĶĶ’’’’ĶĶĶĶō0'IT Resource é @D4C …ĒAq=4BServer Memory’ĶĶ’’’’ĶĶĶĶõ„ B–B’ĶĶ’’’’ĶĶĶĶö†  ŒB–B’ĶĶ’’’’ĶĶĶĶ÷† util ō 4B ź  A ė ’ĶĶ’’’’ĶĶĶĶų†  4B A AHB’ĶĶ’’’’ĶĶĶĶł  ųApA B A 100%’ĶĶ’’’’ĶĶĶĶś   B\BHB ģ ’ĶĶ’’’’ĶĶĶĶū‡ ķ  ī pApA A’ĶĶ’’’’ĶĶĶĶü… ī @ČAČA@’ĶĶ’’’’ĶĶĶĶż… ļ  @ąAąA @’ĶĶ’’’’ĶĶĶĶž‹ š  ń ’ĶĶ’’’’ĶĶĶĶ’… ņ  A°A A°A’ĶĶ’’’’ĶĶĶĶ… ó  A€A A€A’ĶĶ’’’’ĶĶĶĶ1'Uses Resource õ  s  ¬ ’ĶĶ’’’’ĶĶĶĶ1'Uses Resource õ  x  Ä ’ĶĶ’’’’ĶĶĶĶ2'2Miscellaneous connection õ  s  x ’ĶĶ’’’’ĶĶĶĶ1'Uses Resource õ  |  Ü ’ĶĶ’’’’ĶĶĶĶ1'Uses Resource õ  |  ō ’ĶĶ’’’’ĶĶĶĶ2'2Miscellaneous connection õ  x  | ’ĶĶ’’’’ĶĶĶĶ1'Uses Resource õ  ‚  Ü ’ĶĶ’’’’ĶĶĶĶ1'Uses Resource õ  ‚  ō ’ĶĶ’’’’ĶĶĶĶ 2'2Miscellaneous connection õ  |  ‚ ’ĶĶ’’’’ĶĶĶĶ 1'Uses Resource õ  ˆ  Ü ’ĶĶ’’’’ĶĶĶĶ 1'Uses Resource õ  ˆ  ō üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüņqbėZ’ĶĶ’’’’ĶĶĶĶ 2'2Miscellaneous connection õ  ‚  ˆ ’ĶĶ’’’’ĶĶĶĶ 1'Uses Resource õ  Ž  Ü ’ĶĶ’’’’ĶĶĶĶ2'2Miscellaneous connection õ  ˆ  Ž ’ĶĶ’’’’ĶĶĶĶ1'Uses Resource õ  ”  Ü ’ĶĶ’’’’ĶĶĶĶ2'2Miscellaneous connection õ  Ž  ” ’ĶĶ’’’’ĶĶĶĶ1'Uses Resource õ  ™  Ä ’ĶĶ’’’’ĶĶĶĶ2'2Miscellaneous connection õ  ”  ™ ’ĶĶ’’’’ĶĶĶĶ1'Uses Resource õ    ¬ ’ĶĶ’’’’ĶĶĶĶ2'2Miscellaneous connection õ  ™   ’ĶĶ’’’’ĶĶĶĶÅRandomChart"Randomness ChartPath Test’ĶĶ’’’’ĶĶĶĶÅPathDiag"Performance PathPath Test’ĶĶ’’’’ĶĶĶĶÅBrowserPath Test’ĶĶ’’’’ĶĶĶĶm   ’ĶĶ’’’’ĶĶĶĶńcA @AąA°AąA°A @’ĶĶ’’’’ĶĶĶĶéU õ ö ÷ ų ł ś ū ü ż ž ’  ’ĶĶ’’’’ĶĶĶĶŁcA @AąA°AąA°A @’ĶĶ’’’’ĶĶĶĶŃU Ż Ž ß ą į ā ć ä å ę ē č ’ĶĶ’’’’ĶĶĶĶĮcA @AąA°AąA°A @’ĶĶ’’’’ĶĶĶ͹U Å Ę Ē Č É Ź Ė Ģ Ķ Ī Ļ Š ’ĶĶ’’’’ĶĶĶĶ©cA @AąA°AąA°A @’ĶĶ’’’’ĶĶĶĶ”U ­ ® Æ ° ± ² ³ “ µ ¶ · ø ’ĶĶ’’’’ĶĶĶĶ›Už Ÿ   ’ĶĶ’’’’ĶĶĶ͘Uš ’ĶĶ’’’’ĶĶĶĶ’U• – — ’ĶĶ’’’’ĶĶĶ͌U  ‘ ’ĶĶ’’’’ĶĶĶ͆U‰ Š ‹ ’ĶĶ’’’’ĶĶĶĶ€Uƒ „ … ’ĶĶ’’’’ĶĶĶĶzU} ~  ’ĶĶ’’’’ĶĶĶĶwUy ’ĶĶ’’’’ĶĶĶĶqUt u v ’ĶĶ’’’’ĶĶĶĶpT!s x | ‚ ˆ Ž ” ™  ¬ Ä Ü ō                     ’ĶĶ’’’’ĶĶĶĶ]U` a b c d e f ’ĶĶ’’’’ĶĶĶĶWUZ [ ’ĶĶ’’’’ĶĶĶĶRUU V ’ĶĶ’’’’ĶĶĶĶMUP Q ’ĶĶ’’’’ĶĶĶĶLVO T Y ’ĶĶ’’’’ĶĶĶĶFUI J ’ĶĶ’’’’ĶĶĶĶEVH \ _ ’ĶĶ’’’’ĶĶĶĶDVg ’ĶĶ’’’’ĶĶĶĶCTh i j k l m n ’ĶĶ’’’’ĶĶĶĶ2U5 6 7 8 9 : ; ’ĶĶ’’’’ĶĶĶĶ(U+ , - . / 0 1 ’ĶĶ’’’’ĶĶĶĶU! " # $ % & ' ’ĶĶ’’’’ĶĶĶĶV  * 4 ’ĶĶ’’’’ĶĶĶĶU  ’ĶĶ’’’’ĶĶĶĶV < ’ĶĶ’’’’ĶĶĶĶV= ’ĶĶ’’’’ĶĶĶĶT> ? @ A ’ĶĶ’’’’ĶĶĶĶjB o  ’ĶĶ’’’’ĶĶĶĶh    ’ĶĶ’’’’ĶĶĶĶh    üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü¹yˆ•Ų±[’ĶĶ’’’’ĶĶĶĶó= flag(eQueued)’ĶĶ’’’’ĶĶĶĶņ= flag(eQueued)’ĶĶ’’’’ĶĶĶĶš= flag(eQueued)’ĶĶ’’’’ĶĶĶĶļ= flag(eTimesliced)’ĶĶ’’’’ĶĶĶĶī= flag(eTimesliced)’ĶĶ’’’’ĶĶĶĶķ= flag(eTimesliced)’ĶĶ’’’’ĶĶĶĶģ = shape.Title’ĶĶ’’’’ĶĶĶĶė= shape.StatsHeight’ĶĶ’’’’ĶĶĶĶź= shape.StatsY’ĶĶ’’’’ĶĶĶĶŪ= flag(eQueued)’ĶĶ’’’’ĶĶĶĶŚ= flag(eQueued)’ĶĶ’’’’ĶĶĶĶŲ= flag(eQueued)’ĶĶ’’’’ĶĶĶĶ×= flag(eTimesliced)’ĶĶ’’’’ĶĶĶĶÖ= flag(eTimesliced)’ĶĶ’’’’ĶĶĶĶÕ= flag(eTimesliced)’ĶĶ’’’’ĶĶĶĶŌ = shape.Title’ĶĶ’’’’ĶĶĶĶÓ= shape.StatsHeight’ĶĶ’’’’ĶĶĶĶŅ= shape.StatsY’ĶĶ’’’’ĶĶĶĶĆ= flag(eQueued)’ĶĶ’’’’ĶĶĶĶĀ= flag(eQueued)’ĶĶ’’’’ĶĶĶĶĄ= flag(eQueued)’ĶĶ’’’’ĶĶĶĶæ= flag(eTimesliced)’ĶĶ’’’’ĶĶĶ;= flag(eTimesliced)’ĶĶ’’’’ĶĶĶͽ= flag(eTimesliced)’ĶĶ’’’’ĶĶĶͼ = shape.Title’ĶĶ’’’’ĶĶĶĶ»= shape.StatsHeight’ĶĶ’’’’ĶĶĶĶŗ= shape.StatsY’ĶĶ’’’’ĶĶĶĶ«= flag(eQueued)’ĶĶ’’’’ĶĶĶĶŖ= flag(eQueued)’ĶĶ’’’’ĶĶĶĶØ= flag(eQueued)’ĶĶ’’’’ĶĶĶͧ= flag(eTimesliced)’ĶĶ’’’’ĶĶĶͦ= flag(eTimesliced)’ĶĶ’’’’ĶĶĶĶ„= flag(eTimesliced)’ĶĶ’’’’ĶĶĶͤ = shape.Title’ĶĶ’’’’ĶĶĶĶ£= shape.StatsHeight’ĶĶ’’’’ĶĶĶĶ¢= shape.StatsY’ĶĶ’’’’ĶĶĶ͜ = shape.Title’ĶĶ’’’’ĶĶĶĶ“ = shape.Title’ĶĶ’’’’ĶĶĶĶ = shape.Title’ĶĶ’’’’ĶĶĶ͇ = shape.Title’ĶĶ’’’’ĶĶĶ́ = shape.Title’ĶĶ’’’’ĶĶĶĶ{ = shape.Title’ĶĶ’’’’ĶĶĶĶr = shape.Title’ĶĶ’’’’ĶĶĶĶ^ = shape.Title’ĶĶ’’’’ĶĶĶĶX = shape.Title’ĶĶ’’’’ĶĶĶĶS = shape.Title’ĶĶ’’’’ĶĶĶĶN = shape.Title’ĶĶ’’’’ĶĶĶĶG = shape.Title’ĶĶ’’’’ĶĶĶĶ3 = shape.Title’ĶĶ’’’’ĶĶĶĶ) = shape.Title’ĶĶ’’’’ĶĶĶĶ = shape.Title’ĶĶ’’’’ĶĶĶĶ = shape.Title’ĶĶ’’’’ĶĶĶĶ×<p>If you have a license that includes the sources for this model you can change the model data to reflect your own configuration. To do this you need, of course, to run the data browser. You can do this by <cmd Browser>clicking here</cmd>.</p> <p>The different scenario corresponds to a differnt Implementation Path object, which are found in the ImplementationPaths list in the Systems object. I suggest you start by looking at the existing data and seeing how the dataü7 蚦UF’ĶĶ’’’’ĶĶĶĶé there relates to the shapes in the diagrams.</p> <p>The important attributes in the Implementation Path objects are Name, Number and Actions.</p> <ul> <li>The <i>Name</i> attribute is the name as seen in the Performance Path form and is used for selecting the path you want to display.</li> <li>The <i>Number</i> attribute is the default number of times per second this implementation path is executed. You will see in the form for the performance path diagram that there is a multiplier field. This is multiplied to the Number attribute to give the number of executions of this path per second.</li> <li>The <i>Actions</i> attribute is the list of actions in the path  in other words, the work done in the path.</li> </ul> <p>There are two different kinds of action objects; ProcAction and MsgAction. ProcAction is for modelling processor and memory usage and MsgAction is for modelling network traffic. ProcActions and MsgActions are drawn differently in diagrams.</p> <p>The action objects have attributes as follows:</p> <ul> <li>The <i>Name</i> attribute is the name as seen on the action box in the Performance Path diagram.</li> <li>The <i>Utils</i> attribute is a collection of utilization objects. Each utilization object connects to a resource and says how much of the resource it consumes. Utilization objects are discussed in more detail below. If this collection is empty the action wont be displayed on the performance path diagram (as it does not consume any resources).</li> <li>The <i>Sub Actions</i> attribute is a list of actions that make up this action. In other words, they are embedded actions.</li> </ul> <p>There are two ways of setting up the model. The simplest way is for the Implementation Path to have a string of actions, none of which have any Sub Actions. The other way is to use embedded actions, in other words, the Implementation Path has one action but that has a subaction and the subaction has another subaction, and so on. A mix of these methods can also be used. So what's the diffeü;sĪ×5*$ž’ĶĶ’’’’ĶĶĶĶérence between a path of actions and embedded actions? In the static performance model, there is no difference. But when you use the dynamic model, the elapse time of an action includes the elapse time of all its Sub Actions. Especially when modelling memory usage, this is really significant because memory is consumed when the Sub Actions are being executed.</p> <p>Actions have a set of UtilResource objects that define how the actions use the IT Resources. I shall describe IT Resources first.</p> <p>IT Resources are used to define things like what processing power is available, how much memory is available, what disk units are available. There are three kinds of IT resource, as follows:</p> <ul> <li><i>eFixed</i>. This is for resources like memory where the action takes up a certain number of the available units for the duration.</li> <li><i>eQueued</i>. This is for resources like networks where the actions queue to use the resource, and, when it get to the front of the queue, takes up all of the resource until it has finished. Thus if there are 1000 units available every second, and the action takes up 100 of them, then the duration of the action is the 0.1 seconds plus any time for queuing.</li> <li><i>eTimesliced</i>. This is for resources like processing in which actions share a resource with other actions. Thus if there are 1000 units available every second, and the action takes up 100 of them but it is one of 3 actions running in parallel, then the duration of the action is 0.3 seconds.</li> </ul> <p>Note that eQueued and eTimesliced IT resources can be used to calculate a duration. This leads to an important constraint on the model data. If you want to run a dynamic performance model (also known as a queuing model) then each action must have one and only one utilization specified as either a eQueued or a eTimesliced resource. Ah, I hear you say, but I have an action that is queued to begin with and then uses some processor. The solution is to model the action as a queued action and haüąˆ¦—Œ æ’ĶĶ’’’’ĶĶĶĶéve the processor consuming action as a sub-action to it. This works because the duration of an action also includes the duration of all its sub-actions. This means for instance that eFixed resources are held for the complete duration  which is roughly what happens. For instance, memory is used even if the action is waiting for a sub-action to complete.</p> <p>A list of the significant attributes for IT resources is as follows:</p> <ul> <li>The <i>Name</i> attribute is the name as seen on the resource box in the Performance Path diagram.</li> <li>The <i>Category</i> attribute defines whether the resources is eFixed, eQueued or eTimesliced. In the diagram the funny icon on the top left of the resources indicates which it is. If there is something that looks like a ladder, it is an eQueued resource. If there is something that looks like the planet Saturn but with two rings, it is a eTimesliced resource. If it is blank, it is an eFixed resource.</li> <li>The <i>Units</i> attribute is a number of units available. For eQueued and eTimesliced resources this is the number of units available every second.</li> <li>The <i>Number</i> attribute is the number of resources. Thus the number of units available for is Number times Units, but for eQueued resources you get a multi-service queue not a single-service queue.</li> </ul> <p>The UtilResource object is connected to both the action and the IT resources. It defines the utilization, but it's a bit more complex than just a single percentage figure. The significant attributes are as follows:</p> <ul> <li>The <i>Resource</i> attribute defines the IT Resource this utilization applies to.</li> <li>The <i>Imp Action</i> attribute defines the action the utilization is for. Note this and other reference attributes are defined as inverses, so if you created this object by adding to the Utils list in the action then this attribute is set up automatically.</li> <li>The <i>Units Util</i> attribute. Each time the action runs it consumes this number of resource uniüü¤ą«… C’ĶĶ’’’’ĶĶĶĶlts.</li> <li>The <i>Background Units</i> attribute. These are the number of units consumed even if the action is never executed.</li> <li>The <i>Util By User</i> attribute. Sometimes utilization depends on the number of users rather than by the number of times the action is run. For instance there may be a copy of the program for each user, rather than a single copy run when it is needed. The number of users is specified by the form that is used to start a run of the path performance model.</li> </ul> <p>To summarize, the utilization is specified by the formula:</p> <cf> BackgroundUnits + A x UnitsUtil + U x UtilByUser </cf> <p>where A is the number of actions per second and U is the number of users connected.</p> <p>I recommend that you start by setting up a resource for processing and another for memory of every machine in the path. Most actions then have two UtilResource objects  one to connect to the processing resource and another to connect to the memory resource. You can add additional resources for disk and so forth, if you like depending on how complex you want to make your model.</p> ’ĶĶ’’’’ĶĶĶĶ× é é é l ’ĶĶ’’’’ĶĶĶĶ D<p>In this section, I will focus on commercial, on-line applications. Furthermore as this is a short document, I will assume we are confronted with a design that has three layers: presentation layer, processing layer and database layer. Furthermore I will not be interested in the detailed performance within these layers.</p> <p>In this configuration what then are the performance challenges? Put simply they are:</p> <ul> <li>Many users</li> <li>Many transactions</li> <li>Many searches</li> </ul> <p>We discuss each in turn.</p> <p><b>Many Users</b></p> <p>The problem of many users is illustrated by the example called "Simple App". (<cmd PathDiag>Click here</cmd> to see the list of examples and select Simple App.) This is meant to illustrate having one workstation per user, and using RPC technology to call a service. (Actually ü®Š3ó¢ˆż ’ĶĶ’’’’ĶĶĶĶ!éit was simplified rather severely to illustrated some basic points.) If you run the model for one user there is no problem. But try running it for one thousand users and the server runs out of memory. The reason the model works like this is that for every user there is a memory allocation required in the server; for every client program running in the workstation there is a server program running on the server taking up memory even if it's not being used much. Even if the server program is very skinny it may have a database connection and for many database technologies, each database connection incurs a significant memory penalty.</p> <p>Now try the example called "Web App with Transaction Monitor". The behaviour of the model does not change if you change the number of users. It only changes when you change the number of transactions. You can see this by changing the field "Number of Paths Multiplier" before running the model. A transaction monitor takes input from a server and uses a pool of threads and database connections. Hence the number of threads and database connections it uses is roughly the number of transactions being processed at the same time  a number that is typically orders of magnitude less than the number of users.</p> <p>Web applications have a different problem with many users. In theory everyone in the world could be connected to one web application so the potential number of users is enormous. But if the application is stateless  every input has all the information required to process the message  then there is no real problem. The input messages can be distributed evenly across many web servers by a network router. Stateless applications work for reading web pages and for searches. If you try Google and look at the web input command (visible at the top of the page) you will see not only the keywords requested but, if you have asked for a next page or two, the start number in the list. In short it has all the information needed so the input can be stateless. Thus ifüN-Ć* B­ē!’ĶĶ’’’’ĶĶĶĶ"é they have a hundred servers the input message can be routed to any of them. The disadvantage of this approach is that the search engine can't extract 100 hits for your query, store them away somewhere, and process the next page by simply giving the next ten from the list  they have to redo the search. But since most people never get further than the first page, there are huge advantages in being stateless  the clever boys and girls made the right decision.</p> <p>But when you buy something over the web, you typically go through a multi-step process and that means the server application must be stateful  it must know which step you are on and it must also have stored the data from the previous steps. There are several ways of implementing this and I will discuss two.</p> <p>One is to ensure all messages with the same network address go to the same server. The network address is a number and is normally represented something like 65.201.236.045. The first point is that although the IP address is theoretically any 32 bit number, the numbers actually used are very unevenly distributed. Thus, trying to specify different ranges of IP address for each server is likely to run into trouble, especially as you will want in the future to move from 10 servers to some higher number. Therefore it is best if first hash the number to get something more random. Supposing we have 10 servers, then having got our random number we can then take the remainder from a division by 10 giving us a number from 0 to 9, which can be used to identify the web server. So how even is the result? In the section on <ref ModelRand>modelling randomness</ref> discusses this issue. To cut a long story short  it isn't very evenly distributed.</p> <p>Another solution to the state problem is to have a single server, or a database, holding the state. When an input reaches one of many web servers, the web server calls the state-holding server and finds out what the user was doing. There is obviously more of an overhead with this aü““żŹÓĄ*("’ĶĶ’’’’ĶĶĶĶ#épproach but the input messages can be evenly distributed across the servers using a round robin assignment of messages to server. When the stateful conversation with the user is finished, the state can be deleted.</p> <p><b>Many Transactions</b></p> <p>More transactions means more processing power is required, more IO will be done and more memory used. In the old days, we implemented such systems with large mainframes, and still today a single big server is a viable option for many applications. But it may be attractive to split the work among many, smaller servers because you can scale out and many smaller servers might be cheaper than a few big ones. There are two ways of scaling out. One is to split the database. This is illustrated below.</p> <diag id = "multappsone"><p>The other option is to have one database server, but have many application servers. This is illustrated below.</p> <diag id = "multappstwo"><p>The obvious advantage of the second approach is that it may be difficult to split the database into smaller databases. Thus the first point to address is when can you and when can't you split the database.</p> <p>Tables of data from a performance perspective, typically fall into two categories: large volatile tables and many small, relatively stable tables. The large volatile tables typically capture a record of the business actions while the small, relatively stable tables provide reference material such as look up tables, customer tables and product tables. The basic idea is therefore to split the large, volatile tables across several tables and duplicate the small, relatively stable tables  one copy for each database. The duplication can be synchronized with two phase commits, but it is frequently safe to broadcast changes to all copies using technology such as message queuing. The main questions are: how can the large tables be split and, if split, are the performance gains realized?</p> <p>The answers to these questions are, of course, totally application dependent. If the lü²žpq]ēņŠ#’ĶĶ’’’’ĶĶĶĶ$éarge table contains order information, there is little problem splitting a large table into many small tables. If the large table contains bank accounts then you have to find a way of splitting the accounts amoung many small tables. This can of course be done using account number ranges. But one account may be used to process a major companies payroll and another account might be forgotten by its owner. Furthermore the usage of account will change and any fine tuning in the account number ranges will slowly deteriorate.</p> <p>There are additional considerations that need to be investigated before splitting what is logically a single table into many smaller tables. These include:</p> <ul> <li>Searching. You may want to search across all rows of the large logical table. This will be painful if the the table is spread across many machines.</li> <li>Batch runs, like bank interest accrual or processing standing orders, may need to process all accounts and will be more complex if the data is spread across many machines.</li> </ul> <p>There is therefore a good case in many applications for having a single monolithic database, so what about the option of having many application servers all using a single, large database server.</p> <p>The basic question in this scenario is  how big is the database server. Suppose a single transaction does 5 database manipulation commands (select, update, etc.) If the application and the database are on one machine, there is one input and one output network message, but if there are separate application servers then there are an additional 5 input and 5 ouput network messages for transmitting the database commands to the database server. When I talk to people about this, they always say  the overhead of sending a message is small. Well, yes it is, but so is the overhead of doing one database command or processing application logic. The important question is not  is it small?  it is  is it small relative to all the other work needed to process the transaction? üü8߬ź Aņ$’ĶĶ’’’’ĶĶĶĶ%é and the answer is no. But you can reduce the network traffic by using caching or by using database procedures. For instance, if you convert the 5 database manipulation commands into one database procedure call then you cut back the additional network commands to one input and one output message on the database server. However much of the transaction processing logic has now moved into the database procedure code  the database server now has a load that is almost equivalent to putting all the application transaction logic on the single machine.</p> <p>So what about the other way of reducing network traffic  caching the database data on the application servers. You have to be very careful with a caching implementation to ensure that it is safe because you must be careful you don't subvert the transactional ACID properties, for instance, by allowing application servers to read or update data records they haven't locked. But the point of discussion here is  is application server caching effective? By its very nature it is application dependent. Observe though that to reduce 5 database access network messages to 1 or 2 say, the cache has to have a high hit rate. The only way to achieve a high hit rate is to route the traffic to the app server that is most likely to have touched the same objects before. This probably means some data dependent routing which will always have a less even distribution than a round robin distribution and probably a less even distribution than a random distribution. And if a good data distribution schema exists, have you every thought about distributing the database itself? That will most likely be even more efficient.</p> <p>These scenarios are modelled by the Implementation Paths  "App Server and DB" and "One Server". They show the single server (which is the same resource used in both paths) has a greater loading.</p> <p>I hear about many organizations use the many servers configuration, but I really wonder whether they are seeing any benefits. If the databaseü‘–§ BZÄ%’ĶĶ’’’’ĶĶĶĶ&é server is running database procedures I would be surprised if the load on the big server is more than 30% greater than the load on the database server in the first case, and in some cases much less. If so, I really wonder whether the economics of buying lots of small servers really stack up when the additional configuration complexity and operating costs are taken into account.</p> <p>Having separate, and maybe multiple, app servers comes into its own if the data processing logic uses more than one database because then the backend servers are smaller and cheaper. This is good for scalability and, if it's not very cost effect, they can be merged. You should build the design so you can add new servers easily.</p> <p><b>Many Searches</b></p> <p>One reason for separate databases is for searching. Searching is intensive on processing power, memory and IO. In a system with cache it can fill the cache up with data that is of no interest to other running processes. Thus searches have a big impact on other activity. It is highly desirable to move them off the platform that does the transaction updates. This can only be done cleanly if the searches use their own copy of the database. If I were implementing the Amazon application this is how I would do it (and I wasn't involved and don't know what they did.) I would split the database into two  a products database and an orders database. The products database would be largely used for searching. I would then replicate the products database and build a mechanism for updating all the databases in parallel. A broadcast, using message queuing, of all updates would probably suffice. Each search server would then have their own copy of the products database. I would route similar searches to one server, but still keep a complete copy of the product data on all search servers so that I can change the routing dynamically according to changing load.</p> <p><b>Using Modelling</b></p> <p>Modelling the performance helps you think about the issues and forces yoü+[³ćAiČ&’ĶĶ’’’’ĶĶĶĶ'Æu to confront your assumptions. Modelling is hard, but remember the alternative is guess work. Guessing is easy when you can find a working example of an application that is of similar or greater size, but otherwise is hard. A major uncertainty in comparing applications to see if they are of similar size is the database design. It only takes a few extra indexes to alter the performance profile radically.</p> <p>If there is uncertainty, you should do a proof of concept study. This will give you confidence on the speed of the technology and, if you stress test it, thresholds and bottlenecks. It is never going to be accurate but gives some assurance. You need to be aware that real applications go much slower than test applications. The reason is that the additional complexity of real applications costs  more memory, more data (which means less effective caching), more indexes, more background processing, and more random input.</p> ’ĶĶ’’’’ĶĶĶĶD  é! é" é# é$ é% é& Æ' ’ĶĶ’’’’ĶĶĶĶ(ļ<p>There are (at least) five additional performance features that change the model. They are caching, pooling, distribution of input messages across servers, locking and piggy backing. These are examples of aspects of performance that may explain the difference between the model and reality.</p> <p><i>Caching</i> can be modelled by reducing an action's utilization of a resource. The degree to which the utilization is reduced is a function of the cache hit rate, and you can model cache simply by reducing the utilization. But there are (at least) two problems with this approach to modelling caching. One is that finding the hit rate is hard. Take a disk cache as an example. In general they are very effective. Indexes and the blocks at the end of files tend to cache very well. (The blocks at the end of the file are often holding all the newly created objects.) But the rest is much more difficult to estimate. One reason for this difficulty is modelling the impact of writes. You cannot reuse a buffühbF?Z '’ĶĶ’’’’ĶĶĶĶ)éer in a cache until the write is done. A sophisticated cache can steal idle time to write ahead, to write the buffer before the buffer is needed for another read. Unfortunately to make our model we want to mangle all these competing effects into one number, the hit rate. The other problem is catering for actions that purge the cache. For instance suppose a process does a large serial read of the data (for instance in a search). It reads in a lot of data into cache that is of little use to the other processes and may purge out indexes and so forth. The consequence is that there is a hiccup in the performance as the cache is rebuilt and performance returns to what it was before. </p> <p><i>Pooling</i> is a set of resources that can be used across multiple concurrent paths. The model does allow you to specify that there are n copies of a particular resource. This does not quite model pooling properly. For instance, you may model the App Server having 10 copies of App Server memory and 10 copies of App Server processing resource. But the model does not ensure that the memory usage and the processor usage applies to the same server, in effect it just multiplies the available memory and processing power by 10 and treats it as if it were a single big machine.</p> <p>The other form of pooling you may want to model would be a pool of, for instance, database connections. What you would want to handle is that unused pool copies still take resources, in particular memory. The model here is not sophisticated enough to handle this.</p> <p><i>Distribution of input messages across servers</i> I have discussed in a section above on modelling randomness. We can compensate for the unevenness of distribution by under configuring the number of servers. It would be possible to extend the logic to model this more effectively but we would need a range of different facilities to distinguish between different policies for distributing the messages. Some distribution patterns are well known like random and round robiü©Ķµ-6³#(’ĶĶ’’’’ĶĶĶĶ*¹n, but many organizations would like to tailor the model for their own flavour of data range routing.</p> <p><i>Locks</i> are like a resource in that there may be a queue waiting for the lock to become available, so in theory it is possible to model locks. The problem is that we would need to define a resource for every lock and given there are hundreds of locks in a system this is impractical.</p> <p><i>Piggy backing</i> is when a resource can service another action that happens to need the service at the same time. For instance, consider a message queue sending a message. If two messages need sending at the same time, then they can be grouped together and only one message need be transmitted over the network.</p> <p>Clearly the performance model here is not comprehensive, but if it was, there would be much to do to make it useful. First, you need good metrics and that can almost certainly only be obtained by making measurements on a real system. Second, you would need to validate the model by building a model for an existing system and finding out if the model matches reality (and altering it if it doesn't). Only then are you in a good position to start extrapolating the model for a new application and a new load, which must of course be implemented with similar technology. Even then, if you look at the points made in this section, many of them have a non-linear impact on performance with respect to load so uncertainties still remain.</p> ’ĶĶ’’’’ĶĶĶĶ ļ( é) ¹* ’ĶĶ’’’’ĶĶĶĶ+<p>Many aspects of performance hinge on the question  how many actions are running in parallel at one time. The simple model described in the previous section assumes the answer to this question is the same as the number of paths running per second. This assumption is, of course, wrong. To do better we can emulate the running paths. The second level performance model does this.</p> <p>This model uses the same path diagrams shown in the previous section. <cmd PathDiag>Click here</cmd> to show it again. After yüæŠź%}¦ž)’ĶĶ’’’’ĶĶĶĶ,éou have chosen the path and got the diagram displayed (as per the previous section), use the <i>Run</i> menu command on the menu bar to see the emulation. The Run menu command displays the Run dialogue. The best option for seeing these models is to let it default to the Step option, so just press GO. With this option whenever you press the right mouse button, or the keyboard, the model emulates a second's worth of work.</p> <p>Emulation is based on the idea of sending, what I call, tokens down the path. As a token lands on an action it consumes resources. The model calculates the total resource consumption as it goes along. The tokens are fed into the paths randomly as discussed in the section on modelling randomness.</p> <p>Resources come in three flavours  Time sliced, Queued and Fixed. The funny icon on the top left hand corner of a resource in the diagram indicated which of these three the resources belongs to.</p> <p><i>Time sliced</i> resources share the resource equally among the tokens actively using the resource. An example of a time sliced resource is processing. The icon looks rather like the planet Saturn but with two rings not one. It was originally meant to look like a clock with cuts down it, but I thought putting all the detail on the clock face would make it look messy.</p> <p><i>Queued</i> resources have a queue as you would expect. Examples are disk IOs and network resources since a network adapter can only send one message at a time. The icon for a queue looks a bit like a ladder.</p> <p><i>Fixed</i> resources just have something that can be used up with no controls on its usage. An example is memory. There is no icon.</p> <p>For both fixed and queued resources there is a question of what happens if a threshold is exceeded. The model currently does not address this issue; for instance, it will happily use 110% of memory. The utilization box will go red but that is the only indication. The model could be extended to put in an extra load when a threshold is exceeded.</p> üĪ»Üe~ĀĘ*’ĶĶ’’’’ĶĶĶĶ-\<p>Fixed resources like memory are consumed for the elapsed time of the action. But some actions have embedded actions (called sub-actions) and the master action continues, albeit suspended, while the sub-actions do work. The path called "Web App with Transaction Monitor" is an example of using sub-actions. The rectangles enclosing the follow on sub action boxes shows that the first action is suspended while the other actions are executed. Modelling with sub actions makes a significant difference to factors like memory utilization that are Fixed resources.</p> <p>With queuing we can start thinking about creating an accurate model. The problems as always is the choice of actions and the metrics. In capacity management studies they monitor the performance and then use the metrics they have gathered to build the model. The results are impressive.</p> ’ĶĶ’’’’ĶĶĶĶ + é, \- ’ĶĶ’’’’ĶĶĶĶ.`<p>The first level model is built on the notions of actions, paths and resources. This is illustrated in <fig pathmod>.</p> <diag id = "pathmod"><p>A path is a string of actions. In our example we have a workstation that sends a message over a network to a server. The basic path is workstation, message into server, server, message out from server, and finally workstation. Clearly each action may be split into several actions; modelling can almost always be done at many different levels of detail. In our example the server processing has been split into RPC (Remote procedure call) technology, server application and server database processing.</p> <p>To have a complete model you will need many paths, but often it is sufficient to ignore inputs that are very rare. Note too that many different kinds of transaction may have a similar path and we can treat them all as one path. On the other hand, if one kind of transactions has different paths for different input data then we treat these as distinct paths.</p> <p>Each path has a number that is the number of times a second the path is executed.</p> <p>Actions üjQ]ś{:Ę+’ĶĶ’’’’ĶĶĶĶ/éconsume resources. In <fig pathmod>, the resources are shown below the path and a line goes from every action to every resource that the action uses. The resources are the workstation processing, the network line, the server processing and the server memory. Again you can go into more levels of detail by identifying more and more resources. For instance you may model the disk IOs or even the channels to the disk.</p> <p>Each resource has a number associated with it that represents the number of resource units that are available in a second. (We could choose a different unit of time, but using the unit of one second works well for IT systems.) For instance a disk may be able to do 40 IOs in one second so the number of resource units for a disk resource would be 40. In the example, memory has 1000 units and processors have 100. I also allocated both the workstation and the server 100 resource units. This does not mean that they have equal performance. All it means that when we come to document resource utilization we use the action's percentage processor utilization not the absolute number of MIPs. It does not matter what the resource unit actual represents so long as the resource and the users of the resource have consistent units. It's like saying it doesn't matter if we measure in metres or feet and inches so long as either everybody uses metres or everybody uses feet and inches.</p> <p>Each action uses one or more resources, and for each, it consumes some resource units, called the UnitsUtil attribute in the model. Calculating the utilization of the resource is done by adding up two factors  background utilization and action utilization. The background utilization is how much the application (and operating system, etc) is using when it is doing no work. You can specify the background utilization as a base load plus an additional load based on the number of users. Background utilization is particularly significant for memory utilization because there are many case where memory usage is veü’~ É<ŁC/,’ĶĶ’’’’ĶĶĶĶ0éry sensitive to the number of users logged onto the system. Action utilization is the resource used by actually doing some work. It is calculated using the UnitUtils attribute for each action. For each resource we add together the UnitUtils for all the actions that use that resource. We then multiply this number by the number of paths executed in a second. This result of this calculation is the number of resource units consumed by the paths each second. Divide the total units used by the number of resource units available and we have our resource utilization.</p> <p>The resource utilization is illustrated in our diagram by the green vertical rectangles in the resource boxes. If the utilization is above a limit, the rectangle will be red. If there is vital data missing  i.e. the model is incomplete  the rectangle will be orange.</p> <p>This very simple model is illustrated by <cmd PathDiag>clicking here</cmd>. You should get a form when you do the click. This form lets you select a path; click on "Simple Path" and press GO and you should get a diagram a bit like the one illustrated above. You can select one of the other paths which are discussed below. You can also change the number of users and the "Number of Paths Multiplier". This later field is to allow you to change the number of times the path is called per second without having to update the model data. Try changing this field to 10 or 100 and you will see what I mean.</p> <p>This first level performance model does not take you much beyond back-of-the-envelop style calculations. They are not useful for predicting the behaviour of real systems because they are not accurate enough. But they can identify configurations that definitely wont work. They can also be useful for clarifying thinking about performance and for comparing different designs. There are two example paths in the example  <cmd PathDiag>click here</cmd> to redisplay. One is called "One Server" and the other "App Server and DB". The former has a single server, the lattüŠ”äĀ›J-’ĶĶ’’’’ĶĶĶĶ1‘er has separate servers for the application program and the databases. The application and database actions on each are the same. The database server is four times more powerful than the app servers. The DB Connection actions are greater in the App Server and DB scenario because they have to send messages across the network, which incurs a considerable processing load. What you see is that the performance of the One Server scenario is slightly less than the other scenario in spite of the fact that it has only one machine that is the same size as the database server in the App Server and DB scenario. The One Server scenario should be significantly cheaper and easier to operate. But of course you might want to dispute my assumptions, in which case you can  just change the utilization rates for the various actions and rerun the model. Go to the section on <ref change>Changing the Model Data</ref>.</p> ’ĶĶ’’’’ĶĶĶĶ`. é/ é0 ‘1 ’ĶĶ’’’’ĶĶĶĶ2%<p>A simple model to illustrate randomness can run by <cmd RandomChart>clicking here</cmd>.</p> <p>This model allocated a series of Slots  the number of slots is defined by the parameter 'Number of Slots'. Into these Slots are put some Things  the number of Things is defined by the parameter 'Number of Things'. The model randomly puts Things into Slots. When you press "Go", a bar chart is displayed. The bar chart shows how many Things where put into each Slot. For instance, if you don't change any parameters then 100 Things are randomly put into 10 slots. Mostly you find that the Slot with the most Things in it has about 14 Things in it, and the Slot with the least, has about 6 Things in it. But the maximum and minimum vary widely. What is clear after doing this a few times is that it isn't very even.</p> <p>By default this model tries to be as random as possible. (It uses the Microsoft CryptGenRandom function that was provided to help people like me write encryption code). But if you set the 'Use Pseudo Random' to true (click on this field anüĀM@ĆĮOŒN.’ĶĶ’’’’ĶĶĶĶ3éd you will be provided with a popup list of 'true' and 'false'), the model uses a pseudo random function instead. (It uses the C rand() function.) Try using the model a few times with this set and you will see that the bar charts it generates are exactly the same. Pseudo random functions return different random number every time you call the function, but the sequence is dictated by what is called the seed. You can see how this works by setting the 'Pseudo Random Seed' parameter. Every time you run the model with a different seed you get a different sequence of random numbers. Run the model with the same seed value and you get the same sequence of random numbers. So why would a modeller want to use pseudo random numbers? The answer is repeatability. If you run the same test with a truly random sequence of numbers (or as random as Microsoft can make them) then every run has a different result. But if you want to repeat a run with another parameter changed slightly, the only way to get repeatability is to use pseudo random numbers.</p> <p>Random functions are used extensively in modelling IT systems. Two examples will suffice. One is the effect of distributing messages randomly across a collection of servers. If you want to model 1000 input messages being spread over 10 servers using the model above, set Number of Slots to 10 and Number of Things to 1000 and run the model. You will probably find the messages have been fairly evenly distributed  perhaps the maximum is 120 and the minimum is 80. At this point you might think that all is well, but perhaps you are asking the wrong question. The performance critical factor is not how many arrive over a long period, it is, how many arrive at around the same time. So instead of modelling 1000 over a minute, try modelling 20 messages over one second. How evenly are these distributed? Try it; set Slots to 10 and Things to 20. It's not at all that even. I tried it three times and got a maximum of 6, 4 and 5.</p> <p>The other example is modelling randoüuˆŹ ;‰™/’ĶĶ’’’’ĶĶĶĶ4Tm input. Most organizations know that in a peak hour they have x transactions, and, for new applications, they are prepared to estimate the peak hour throughput requirements. But if, say, an organization has 3600 inputs distributed randomly in a peak hour, how many transactions are there in a peak second? The answer is not one  that would be a completely even distribution. In the performance model discussed in the next section the approach I have taken is as follows. The model takes 1000 inputs and work out how many seconds that corresponds to, calculating a target rate of n per second. Thus, if n is 10, the model takes 100 seconds. It then builds a list of start times in milliseconds. If the period is 100 seconds, the model calculates a random number between 0 and 100,000 for each of the 1000 inputs and that is the start time list. It then sorts the list to put the inputs in order. In this case the start time list takes 100 seconds, and at the end of the period it starts again at the beginning of the list. This approach is a compromise between what's realistic and what can be implemented. Mind you, it's hard to know exactly what is realistic. Taking a time period of, say, an hour and creating a start list for all the inputs for the hour would probably create a more uneven distribution. But on the other hand, in a peak hour perhaps many users are working the system as fast as they can and that means each of them putting in input quite evenly, say once a minute.</p> <p>The best way is to have an accurate picture of how inputs come into a system is to capture a log from an existing system.</p> ’ĶĶ’’’’ĶĶĶĶ%2 é3 T4 ’ĶĶ’’’’ĶĶĶĶ<p>In this section I describe modelling performance in three levels of difficulty, starting with a simple model and adding additional complexities. But before that, there is an introduction to a very simple diagram that illustrates the nature of randomness.</p> ’ĶĶ’’’’ĶĶĶĶ5T<p>Since even desktop PCs now have clock rates of over 1 Gigahertz, it is hard to beO|*Ų8ä«0’ĶĶ’’’’ĶĶĶĶ6élieve that there are still performance and scalability problems. Taking Moore's law at face value  the complexity of chips doubles every 2 years  and assuming that chip complexity translates into performance, then a PC today should be 1000 times more powerful than a PC twenty years ago. And the successor to the small machine that twenty years ago that handled 10 users, should now be able to handle 10,000 users. It can't.</p> <p>One reason why chip improvements have not translated into system performance is that while raw processing performance has indeed improved enormously over 20 years, as have other performance elements such as disk densities, some important components haven't changed that much at all. The number of random disk reads or writes per second is approximately twice as many today as it was twenty years ago, discounting the affect of caching. DRAM memory chips holds much more data than its equivalents twenty years ago but the time to read a word of data is only about twice as fast. But by far the most significant reason why applications today aren't a thousand times faster than their predecessors twenty years ago is that the software is different; people develop multi-tier applications rather than mainframe applications, and they use system software that is much more extravagant in its use of processor and memory resources.</p> <p>That said, it is probably true that fewer organizations today have performance problems than in the past. It is evident that you can build high performance applications using any from a large number of database and middleware products, including open source products. Setting aside the few that have done something stupid (usually because they believed some industry hype), the organizations that truly have performance problems in spades are the ones who are trying something very ambitious, like a large web application or supporting a large government system.</p> <p>Modelling can be used in IT systems design to estimate how much hardware to buy, but inü£łóß:ź]]2’ĶĶ’’’’ĶĶĶĶ7Ń practice, it rarely is. The reason is that systems  especially multi-tier systems  are so complex that it is extremely hard to build an accurate model. The best practical approach is to benchmark a running system and then try to extrapolate the performance to calculate how a similar system will perform under different loads. Even then a straightforward extrapolation is often not possible, and one of aims of this tutorial is to point out why. Thus I don't have a series of magic incantations that can ensure you build an accurate performance model for every eventuallity, rather, I take the line that if you have a swamp to cross it is best to know where the crocodilles might be hiding.</p> <p>The next section introduces a simple performance model. This is followed by a discussion of some basic performance issues in commercial, on-line systems and uses the model to illustrate the effects of different configurations.</p> <p>Finally this is a <b>WeaverBird</b> model and that means that the diagrams are generated from the model data (except diagrams embedded in the text.) Thus you can change the model data and different diagrams will appear. This means that you can write your own modelling example using the code I have developed for you. If you want to do this, read the section on Changing the Model Data first, since this explains how the model data is structured. To change the model data, you need the version of the developers license that includes example models.</p> ’ĶĶ’’’’ĶĶĶĶT5 é6 Ń7 žżŁ”^„7ImportĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢ’ĶĶ<Ć>Performance Modelling Tutorial      <For WeaverBird version 2008v2JCopyright (c) 2008, Polyphony IT Ltd ? ’ĶĶU¶Introduction  8 ’ĶĶė¶ModelRand*Modelling Randomness  9 ’ĶĶK ¶2Simple Performance Model  : ’ĶĶ  ¶4Queuing Performance Model  ; ’ĶĶ÷ ¶Complexities  < ’ĶĶ4¶ Perf6Some Issues and Approaches  = üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüDŗoꄌfj’ĶĶż'2Internal network message   ’ĶĶ'&Workstation output  € ’ĶĶ’’’’ĶĶĶĶ€A'’ĶĶ’’’’ĶĶĶĶA'’ĶĶ’’’’ĶĶĶĶ~A'’ĶĶ’’’’ĶĶĶĶ}A'’ĶĶ’’’’ĶĶĶĶ|A'’ĶĶ’’’’ĶĶĶĶ{A'’ĶĶ’’’’ĶĶĶĶzA'’ĶĶ’’’’ĶĶĶĶyA'’ĶĶ’’’’ĶĶĶĶxA'žüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü7¾1•“|’ĶĶ–¶change0Changing the Model Data  > ’ĶĶ 1'Uses Resource õ  s  ¬ ęRRC’ĶĶp 1'Uses Resource õ  x  Ä 7ńbC’ĶĶÓ 2'2Miscellaneous connection õ  s  x HB’ĶĶL 1'Uses Resource õ  |  Ü ĄGeC’ĶĶÆ 1'Uses Resource õ  |  ō Ā7™C’ĶĶ 2'2Miscellaneous connection õ  x  | HB’ĶĶ‹ 1'Uses Resource õ  ‚  Ü ¬C’ĶĶī 1'Uses Resource õ  ‚  ō æGeC’ĶĶQ 2'2Miscellaneous connection õ  |  ‚ HB’ĶĶŹ 1'Uses Resource õ  ˆ  Ü L®B’ĶĶ- 1'Uses Resource õ  ˆ  ō + C’ĶĶ 2'2Miscellaneous connection õ  ‚  ˆ HB’Ķ͉ 1'Uses Resource õ  Ž  Ü žŸB’ĶĶģ2'2Miscellaneous connection õ  ˆ  Ž HB’ĶĶe1'Uses Resource õ  ”  Ü Ū] C’ĶĶČ2'2Miscellaneous connection õ  Ž  ” HB’ĶĶA1'Uses Resource õ  ™  Ä |Ī›C’Ķͤ2'2Miscellaneous connection õ  ”  ™ HB’ĶĶ1'Uses Resource õ    ¬ “ÄģC’ĶĶ€2'2Miscellaneous connection õ  ™   HB’ĶĶ’’’’ĶĶĶĶ?h’ĶĶ’’’’ĶĶĶĶ>h’ĶĶ’’’’ĶĶĶĶ=h’ĶĶ’’’’ĶĶĶĶ<h’ĶĶ’’’’ĶĶĶĶ;h’ĶĶ’’’’ĶĶĶĶ:h’ĶĶ’’’’ĶĶĶĶ9h’ĶĶ’’’’ĶĶĶĶ8hžüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü