benchmark.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. <?php
  2. // Copyright (C) 2010 Combodo SARL
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; version 3 of the License.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. /**
  17. * Page designed to help in benchmarkink the scalability of itop
  18. *
  19. * @author Erwan Taloc <erwan.taloc@combodo.com>
  20. * @author Romain Quetiez <romain.quetiez@combodo.com>
  21. * @author Denis Flaven <denis.flaven@combodo.com>
  22. * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
  23. */
  24. require_once('../application/application.inc.php');
  25. require_once('../application/itopwebpage.class.inc.php');
  26. require_once('../application/wizardhelper.class.inc.php');
  27. require_once('../application/startup.inc.php');
  28. require_once('../application/loginwebpage.class.inc.php');
  29. require_once('../application/utils.inc.php');
  30. require_once('./setuppage.class.inc.php');
  31. class BenchmarkDataCreation
  32. {
  33. var $m_aPlanned = array();
  34. var $m_aCreated = array();
  35. var $m_aStatsByClass = array();
  36. public function __construct($iPlannedCIs, $iPlannedContacts, $iPlannedContracts)
  37. {
  38. $this->m_aPlanned = array(
  39. 'CIs' => $iPlannedCIs,
  40. 'Contacts' => $iPlannedContacts,
  41. 'Contracts' => $iPlannedContracts,
  42. 'SubCIs' => 10 * $iPlannedCIs,
  43. 'Incidents' => 2 * 12 * $iPlannedCIs,
  44. 'ServiceCalls' => 1 * 12 * $iPlannedContacts,
  45. 'Changes' => 1 * 12 * $iPlannedCIs,
  46. 'Documents' => 12 * $iPlannedContracts + $iPlannedCIs,
  47. );
  48. }
  49. public function GetPlan()
  50. {
  51. return $this->m_aPlanned;
  52. }
  53. protected function CreateObject($sClass, $aData, $oChange)
  54. {
  55. $mu_t1 = MyHelpers::getmicrotime();
  56. $oMyObject = MetaModel::NewObject($sClass);
  57. foreach($aData as $sProp => $value)
  58. {
  59. $oMyObject->Set($sProp, $value);
  60. }
  61. $iId = $oMyObject->DBInsertTrackedNoReload($oChange);
  62. $this->m_aCreated[$sClass][] = $iId;
  63. $mu_t2 = MyHelpers::getmicrotime();
  64. $this->m_aStatsByClass[$sClass][] = $mu_t2 - $mu_t1;
  65. return $iId;
  66. }
  67. protected function RandomId($sClass)
  68. {
  69. return $this->m_aCreated[$sClass][array_rand($this->m_aCreated[$sClass])];
  70. }
  71. static protected function FindId($sClass)
  72. {
  73. $oSet = new DBObjectSet(new DBObjectSearch($sClass));
  74. if ($oSet->Count() < 1)
  75. {
  76. return null;
  77. }
  78. $oObj = $oSet->Fetch();
  79. return $oObj->GetKey();
  80. }
  81. static protected function FindIdFromOQL($sOQL)
  82. {
  83. $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
  84. if ($oSet->Count() < 1)
  85. {
  86. return null;
  87. }
  88. $oObj = $oSet->Fetch();
  89. return $oObj->GetKey();
  90. }
  91. protected function MakeFeedback($oP, $sClass)
  92. {
  93. $iSample = reset($this->m_aCreated[$sClass]);
  94. $sSample = "<a href=\"../pages/UI.php?operation=details&class=$sClass&id=$iSample\">sample</a>";
  95. $iDuration = number_format(array_sum($this->m_aStatsByClass[$sClass]), 3);
  96. $fDurationMin = number_format(min($this->m_aStatsByClass[$sClass]), 3);
  97. $fDurationMax = number_format(max($this->m_aStatsByClass[$sClass]), 3);
  98. $fDurationAverage = number_format(array_sum($this->m_aStatsByClass[$sClass]) / count($this->m_aStatsByClass[$sClass]), 3);
  99. $oP->add("<ul>");
  100. $oP->add("<li>");
  101. $oP->add("$sClass: ".count($this->m_aCreated[$sClass])." - $sSample<br/>");
  102. $oP->add("Duration: $fDurationMin =&gt; $fDurationMax; Avg:$fDurationAverage; Total: $iDuration");
  103. $oP->add("</li>");
  104. $oP->add("</ul>");
  105. }
  106. public function GoProjections(WebPage $oP, $oChange)
  107. {
  108. // User login
  109. //
  110. $aData = array(
  111. 'contactid' => self::FindId('bizPerson'),
  112. 'login' => 'foo',
  113. 'password' => 'foo',
  114. 'language' => 'EN US',
  115. );
  116. $iLogin = $this->CreateObject('User', $aData, $oChange);
  117. // Assign profiles to the new login
  118. //
  119. $aData = array(
  120. 'userid' => $iLogin,
  121. 'profileid' => self::FindIdFromOQL("SELECT URP_Profiles WHERE name LIKE 'Configuration Manager'"),
  122. 'reason' => '',
  123. );
  124. $iFoo = $this->CreateObject('URP_UserProfile', $aData, $oChange);
  125. // Dimension
  126. //
  127. $aData = array(
  128. 'name' => 'location',
  129. 'description' => '',
  130. 'type' => 'bizLocation',
  131. );
  132. $iDimLocation = $this->CreateObject('URP_Dimensions', $aData, $oChange);
  133. // Project classes
  134. //
  135. $aMyClassesToProject = array('bizDevice', 'bizServer');
  136. foreach($aMyClassesToProject as $sClass)
  137. {
  138. $aData = array(
  139. 'dimensionid' => $iDimLocation,
  140. 'class' => $sClass,
  141. 'value' => '<this>',
  142. 'attribute' => 'location_name',
  143. );
  144. $iFoo = $this->CreateObject('URP_ClassProjection', $aData, $oChange);
  145. }
  146. // Project profiles
  147. //
  148. $aProfilesToProject = array(1, 2, 3, 4, 5, 6, 7, 8, 9);
  149. foreach($aProfilesToProject as $iProfileId)
  150. {
  151. $aData = array(
  152. 'dimensionid' => $iDimLocation,
  153. 'profileid' => $iProfileId,
  154. 'value' => 'Grenoble',
  155. 'attribute' => '',
  156. );
  157. $iFoo = $this->CreateObject('URP_ProfileProjection', $aData, $oChange);
  158. }
  159. $oP->p('Created projections (Cf. login "foo", pwd "foo")');
  160. }
  161. public function GoVolume(WebPage $oP, $oChange)
  162. {
  163. // 1 - Organizations
  164. //
  165. $aData = array(
  166. 'name' => 'benchmark',
  167. );
  168. $iOrg = $this->CreateObject('bizOrganization', $aData, $oChange);
  169. $this->MakeFeedback($oP, 'bizOrganization');
  170. // 2 - Locations
  171. //
  172. $aData = array(
  173. 'org_id' => $iOrg,
  174. 'name' => 'rio',
  175. );
  176. $iLoc = $this->CreateObject('bizLocation', $aData, $oChange);
  177. $this->MakeFeedback($oP, 'bizLocation');
  178. // 3 - Teams
  179. //
  180. $aData = array(
  181. 'org_id' => $iOrg,
  182. 'location_id' => $iLoc,
  183. 'name' => 'fluminense',
  184. );
  185. $iTeam = $this->CreateObject('bizTeam', $aData, $oChange);
  186. $this->MakeFeedback($oP, 'bizTeam');
  187. // 3' - Workgroups
  188. //
  189. $iAnyTeam = $this->RandomId('bizTeam');
  190. $aData = array(
  191. 'org_id' => $iOrg,
  192. 'team_id' => $iAnyTeam,
  193. 'name' => 'trabolhogrupo'.$iAnyTeam,
  194. );
  195. $iTeam = $this->CreateObject('bizWorkgroup', $aData, $oChange);
  196. $this->MakeFeedback($oP, 'bizWorkgroup');
  197. // 4 - Persons
  198. //
  199. for($i = 0 ; $i < $this->m_aPlanned['Contacts'] ; $i++)
  200. {
  201. $aData = array(
  202. 'org_id' => $iOrg,
  203. 'location_id' => $iLoc,
  204. 'name' => 'ningem'.$i,
  205. );
  206. $this->CreateObject('bizPerson', $aData, $oChange);
  207. }
  208. $this->MakeFeedback($oP, 'bizPerson');
  209. // 5 - Servers
  210. //
  211. for($i = 0 ; $i < $this->m_aPlanned['CIs'] ; $i++)
  212. {
  213. $aData = array(
  214. 'org_id' => $iOrg,
  215. 'location_id' => $iLoc,
  216. 'name' => 'server'.$i,
  217. );
  218. $this->CreateObject('bizServer', $aData, $oChange);
  219. }
  220. $this->MakeFeedback($oP, 'bizServer');
  221. // 6 - Incident Tickets
  222. //
  223. for($i = 0 ; $i < $this->m_aPlanned['Incidents'] ; $i++)
  224. {
  225. $aData = array(
  226. 'org_id' => $iOrg,
  227. 'caller_id' => $this->RandomId('bizPerson'),
  228. 'workgroup_id' => $this->RandomId('bizWorkgroup'),
  229. 'agent_id' => $this->RandomId('bizPerson'),
  230. 'title' => 'someevent'.$i,
  231. );
  232. $iTicket = $this->CreateObject('bizIncidentTicket', $aData, $oChange);
  233. // Incident/Infra
  234. //
  235. $iInfraCount = rand(0, 6);
  236. for($iLinked = 0 ; $iLinked < $iInfraCount ; $iLinked++)
  237. {
  238. $aData = array(
  239. 'infra_id' => $this->RandomId('bizServer'),
  240. 'ticket_id' => $iTicket,
  241. 'impact' => 'info on impact '.$iLinked,
  242. );
  243. $this->CreateObject('lnkInfraTicket', $aData, $oChange);
  244. }
  245. // Incident/Contact
  246. //
  247. $iInfraCount = rand(0, 6);
  248. for($iLinked = 0 ; $iLinked < $iInfraCount ; $iLinked++)
  249. {
  250. $aData = array(
  251. 'contact_id' => $this->RandomId('bizPerson'),
  252. 'ticket_id' => $iTicket,
  253. 'role' => 'role '.$iLinked,
  254. );
  255. $this->CreateObject('lnkContactTicket', $aData, $oChange);
  256. }
  257. }
  258. $this->MakeFeedback($oP, 'bizIncidentTicket');
  259. // 7 - Change Tickets
  260. //
  261. for($i = 0 ; $i < $this->m_aPlanned['Changes'] ; $i++)
  262. {
  263. $aData = array(
  264. 'org_id' => $iOrg,
  265. 'requestor_id' => $this->RandomId('bizPerson'),
  266. 'workgroup_id' => $this->RandomId('bizWorkgroup'),
  267. 'agent_id' => $this->RandomId('bizPerson'),
  268. 'supervisorgroup_id' => $this->RandomId('bizWorkgroup'),
  269. 'supervisor_id' => $this->RandomId('bizPerson'),
  270. 'managergroup_id' => $this->RandomId('bizWorkgroup'),
  271. 'manager_id' => $this->RandomId('bizPerson'),
  272. 'title' => "change$i",
  273. );
  274. $iTicket = $this->CreateObject('bizChangeTicket', $aData, $oChange);
  275. // Change/Infra
  276. //
  277. $iInfraCount = rand(0, 6);
  278. for($iLinked = 0 ; $iLinked < $iInfraCount ; $iLinked++)
  279. {
  280. $aData = array(
  281. 'infra_id' => $this->RandomId('bizServer'),
  282. 'ticket_id' => $iTicket,
  283. 'impact' => 'info on impact '.$iLinked,
  284. );
  285. $this->CreateObject('lnkInfraChangeTicket', $aData, $oChange);
  286. }
  287. // Change/Contact
  288. //
  289. $iInfraCount = rand(0, 6);
  290. for($iLinked = 0 ; $iLinked < $iInfraCount ; $iLinked++)
  291. {
  292. $aData = array(
  293. 'contact_id' => $this->RandomId('bizPerson'),
  294. 'change_id' => $iTicket,
  295. 'role' => 'role '.$iLinked,
  296. );
  297. $this->CreateObject('lnkContactChange', $aData, $oChange);
  298. }
  299. }
  300. $this->MakeFeedback($oP, 'bizChangeTicket');
  301. // 8 - Service calls
  302. //
  303. for($i = 0 ; $i < $this->m_aPlanned['ServiceCalls'] ; $i++)
  304. {
  305. $aData = array(
  306. 'org_id' => $iOrg,
  307. 'caller_id' => $this->RandomId('bizPerson'),
  308. 'workgroup_id' => $this->RandomId('bizWorkgroup'),
  309. 'agent_id' => $this->RandomId('bizPerson'),
  310. 'title' => "call$i",
  311. );
  312. $iTicket = $this->CreateObject('bizServiceCall', $aData, $oChange);
  313. // Call/Infra
  314. //
  315. $iInfraCount = rand(0, 6);
  316. for($iLinked = 0 ; $iLinked < $iInfraCount ; $iLinked++)
  317. {
  318. $aData = array(
  319. 'infra_id' => $this->RandomId('bizServer'),
  320. 'call_id' => $iTicket,
  321. 'impact' => 'info on impact '.$iLinked,
  322. );
  323. $this->CreateObject('lnkInfraCall', $aData, $oChange);
  324. }
  325. }
  326. $this->MakeFeedback($oP, 'bizServiceCall');
  327. // 8 - Documents
  328. //
  329. $sMyDoc = '';
  330. for($i = 0 ; $i < 1000 ; $i++)
  331. {
  332. // 100 chars
  333. $sMyDoc .= "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678\n";
  334. }
  335. $oRefDoc = new ormDocument($sMyDoc, 'text/plain');
  336. for($i = 0 ; $i < $this->m_aPlanned['Documents'] ; $i++)
  337. {
  338. $aData = array(
  339. 'org_id' => $iOrg,
  340. 'name' => "document$i",
  341. 'contents' => $oRefDoc,
  342. );
  343. $this->CreateObject('bizDocument', $aData, $oChange);
  344. }
  345. $this->MakeFeedback($oP, 'bizDocument');
  346. }
  347. }
  348. /**
  349. * Ask the user what are the settings for the data load
  350. */
  351. function DisplayStep1(SetupWebPage $oP)
  352. {
  353. $sNextOperation = 'step2';
  354. $oP->add("<h1>iTop benchmarking</h1>\n");
  355. $oP->add("<h2>Please specify the requested volumes</h2>\n");
  356. $oP->add("<form method=\"post\" onSubmit=\"return DoSubmit('Evaluating real plans...', 10)\">\n");
  357. $oP->add("<fieldset><legend>Data load configuration</legend>\n");
  358. $aForm = array();
  359. $aForm[] = array(
  360. 'label' => "Main CIs:",
  361. 'input' => "<input id=\"to\" type=\"text\" name=\"plannedcis\" value=\"70\">",
  362. 'help' => ' exclude interfaces, subnets or any other type of secondary CI',
  363. );
  364. $aForm[] = array(
  365. 'label' => "Contacts:",
  366. 'input' => "<input id=\"from\" type=\"text\" name=\"plannedcontacts\" value=\"100\">",
  367. 'help' => '',
  368. );
  369. $aForm[] = array(
  370. 'label' => "Contracts:",
  371. 'input' => "<input id=\"from\" type=\"text\" name=\"plannedcontracts\" value=\"10\">",
  372. 'help' => '',
  373. );
  374. $oP->form($aForm);
  375. $oP->add("</fieldset>\n");
  376. $oP->add("<input type=\"hidden\" name=\"operation\" value=\"$sNextOperation\">\n");
  377. $oP->add("<button type=\"submit\">Next >></button>\n");
  378. $oP->add("</form>\n");
  379. }
  380. /**
  381. * Inform the user how many items will be created
  382. */
  383. function DisplayStep2(SetupWebPage $oP, $oDataCreation)
  384. {
  385. $sNextOperation = 'step3';
  386. $oP->add("<h1>iTop benchmarking</h1>\n");
  387. $oP->add("<h2>Step 2: review planned volumes</h2>\n");
  388. $aPlanned = $oDataCreation->GetPlan();
  389. $aForm = array();
  390. foreach ($aPlanned as $sKey => $iCount)
  391. {
  392. $aForm[] = array(
  393. 'label' => $sKey,
  394. 'input' => $iCount,
  395. );
  396. }
  397. $oP->form($aForm);
  398. $oP->add("<form method=\"post\" onSubmit=\"return DoSubmit('Loading data...', 10)\">\n");
  399. $oP->add("<input type=\"hidden\" name=\"operation\" value=\"$sNextOperation\">\n");
  400. $oP->add("<input type=\"hidden\" name=\"plannedcis\" value=\"".$aPlanned['CIs']."\">\n");
  401. $oP->add("<input type=\"hidden\" name=\"plannedcontacts\" value=\"".$aPlanned['Contacts']."\">\n");
  402. $oP->add("<input type=\"hidden\" name=\"plannedcontracts\" value=\"".$aPlanned['Contracts']."\">\n");
  403. $oP->add("<button type=\"submit\">Next >></button>\n");
  404. $oP->add("</form>\n");
  405. }
  406. /**
  407. * Do create the data set... could take some time to execute
  408. */
  409. function DisplayStep3(SetupWebPage $oP, $oDataCreation)
  410. {
  411. // $sNextOperation = 'step3';
  412. $oMyChange = MetaModel::NewObject("CMDBChange");
  413. $oMyChange->Set("date", time());
  414. $oMyChange->Set("userinfo", "Administrator");
  415. $iChangeId = $oMyChange->DBInsertNoReload();
  416. $oDataCreation->GoProjections($oP, $oMyChange);
  417. $oDataCreation->GoVolume($oP, $oMyChange);
  418. }
  419. /**
  420. * Main program
  421. */
  422. LoginWebPage::DoLogin(); // Check user rights and prompt if needed
  423. $sOperation = Utils::ReadParam('operation', 'step1');
  424. $oP = new SetupWebPage('iTop benchmark utility');
  425. try
  426. {
  427. switch($sOperation)
  428. {
  429. case 'step1':
  430. DisplayStep1($oP);
  431. break;
  432. case 'step2':
  433. $oP->no_cache();
  434. $iPlannedCIs = Utils::ReadParam('plannedcis');
  435. $iPlannedContacts = Utils::ReadParam('plannedcontacts');
  436. $iPlannedContracts = Utils::ReadParam('plannedcontracts');
  437. $oDataCreation = new BenchmarkDataCreation($iPlannedCIs, $iPlannedContacts, $iPlannedContracts);
  438. DisplayStep2($oP, $oDataCreation);
  439. break;
  440. case 'step3':
  441. $oP->no_cache();
  442. $iPlannedCIs = Utils::ReadParam('plannedcis');
  443. $iPlannedContacts = Utils::ReadParam('plannedcontacts');
  444. $iPlannedContracts = Utils::ReadParam('plannedcontracts');
  445. $oDataCreation = new BenchmarkDataCreation($iPlannedCIs, $iPlannedContacts, $iPlannedContracts);
  446. DisplayStep3($oP, $oDataCreation);
  447. break;
  448. default:
  449. $oP->error("Error: unsupported operation '$sOperation'");
  450. }
  451. }
  452. catch(ZZException $e)
  453. {
  454. $oP->error("Error: '".$e->getMessage()."'");
  455. }
  456. catch(ZZCoreException $e)
  457. {
  458. $oP->error("Error: '".$e->getHtmlDesc()."'");
  459. }
  460. $oP->output();
  461. ?>