benchmark.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  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('Person'),
  112. 'login' => 'foo',
  113. 'password' => 'foo',
  114. 'language' => 'EN US',
  115. );
  116. $iLogin = $this->CreateObject('UserLocal', $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' => 'Location',
  131. );
  132. $iDimLocation = $this->CreateObject('URP_Dimensions', $aData, $oChange);
  133. // Project classes
  134. //
  135. $aMyClassesToProject = array('NetworkDevice', 'Server');
  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('Organization', $aData, $oChange);
  169. $this->MakeFeedback($oP, 'Organization');
  170. // 1' - Services
  171. //
  172. $aData = array(
  173. 'name' => 'My Service',
  174. );
  175. $iOrg = $this->CreateObject('Service', $aData, $oChange);
  176. $this->MakeFeedback($oP, 'Service');
  177. // 1'' - Service subcategories
  178. //
  179. $aData = array(
  180. 'name' => 'My subcategory',
  181. );
  182. $iOrg = $this->CreateObject('ServiceSubcategory', $aData, $oChange);
  183. $this->MakeFeedback($oP, 'ServiceSubcategory');
  184. // 2 - Locations
  185. //
  186. $aData = array(
  187. 'org_id' => $iOrg,
  188. 'name' => 'rio',
  189. );
  190. $iLoc = $this->CreateObject('Location', $aData, $oChange);
  191. $this->MakeFeedback($oP, 'Location');
  192. // 3 - Teams
  193. //
  194. $aData = array(
  195. 'org_id' => $iOrg,
  196. 'location_id' => $iLoc,
  197. 'name' => 'fluminense',
  198. 'email' => 'fluminense@nowhere.fr',
  199. );
  200. $iTeam = $this->CreateObject('Team', $aData, $oChange);
  201. $this->MakeFeedback($oP, 'Team');
  202. // 4 - Persons
  203. //
  204. for($i = 0 ; $i < $this->m_aPlanned['Contacts'] ; $i++)
  205. {
  206. $aData = array(
  207. 'org_id' => $iOrg,
  208. 'location_id' => $iLoc,
  209. 'name' => 'ningem'.$i,
  210. 'email' => 'foo'.$i.'@nowhere.fr',
  211. );
  212. $this->CreateObject('Person', $aData, $oChange);
  213. }
  214. $this->MakeFeedback($oP, 'Person');
  215. // 5 - Servers
  216. //
  217. for($i = 0 ; $i < $this->m_aPlanned['CIs'] ; $i++)
  218. {
  219. $aData = array(
  220. 'org_id' => $iOrg,
  221. 'location_id' => $iLoc,
  222. 'name' => 'server'.$i,
  223. );
  224. $this->CreateObject('Server', $aData, $oChange);
  225. }
  226. $this->MakeFeedback($oP, 'Server');
  227. // 6 - Incident Tickets
  228. //
  229. for($i = 0 ; $i < $this->m_aPlanned['Incidents'] ; $i++)
  230. {
  231. $aData = array(
  232. 'org_id' => $iOrg,
  233. 'caller_id' => $this->RandomId('Person'),
  234. 'workgroup_id' => $this->RandomId('Team'),
  235. 'agent_id' => $this->RandomId('Person'),
  236. 'service_id' => $this->RandomId('Service'),
  237. 'servicesubcategory_id' => $this->RandomId('ServiceSubcategory'),
  238. 'title' => 'someevent'.$i,
  239. 'ticket_log' => 'Testing...',
  240. );
  241. $iTicket = $this->CreateObject('Incident', $aData, $oChange);
  242. // Incident/Infra
  243. //
  244. $iInfraCount = rand(0, 6);
  245. for($iLinked = 0 ; $iLinked < $iInfraCount ; $iLinked++)
  246. {
  247. $aData = array(
  248. 'ci_id' => $this->RandomId('Server'),
  249. 'ticket_id' => $iTicket,
  250. );
  251. $this->CreateObject('lnkTicketToCI', $aData, $oChange);
  252. }
  253. // Incident/Contact
  254. //
  255. $iInfraCount = rand(0, 6);
  256. for($iLinked = 0 ; $iLinked < $iInfraCount ; $iLinked++)
  257. {
  258. $aData = array(
  259. 'contact_id' => $this->RandomId('Person'),
  260. 'ticket_id' => $iTicket,
  261. 'role' => 'role '.$iLinked,
  262. );
  263. $this->CreateObject('lnkTicketToContact', $aData, $oChange);
  264. }
  265. }
  266. $this->MakeFeedback($oP, 'Incident');
  267. // 7 - Change Tickets
  268. //
  269. for($i = 0 ; $i < $this->m_aPlanned['Changes'] ; $i++)
  270. {
  271. $aData = array(
  272. 'org_id' => $iOrg,
  273. 'requestor_id' => $this->RandomId('Person'),
  274. 'workgroup_id' => $this->RandomId('Team'),
  275. 'agent_id' => $this->RandomId('Person'),
  276. 'supervisor_group_id' => $this->RandomId('Team'),
  277. 'supervisor_id' => $this->RandomId('Person'),
  278. 'manager_group_id' => $this->RandomId('Team'),
  279. 'manager_id' => $this->RandomId('Person'),
  280. 'title' => "change$i",
  281. 'description' => "Let's do something there",
  282. );
  283. $iTicket = $this->CreateObject('NormalChange', $aData, $oChange);
  284. // Change/Infra
  285. //
  286. $iInfraCount = rand(0, 6);
  287. for($iLinked = 0 ; $iLinked < $iInfraCount ; $iLinked++)
  288. {
  289. $aData = array(
  290. 'ci_id' => $this->RandomId('Server'),
  291. 'ticket_id' => $iTicket,
  292. );
  293. $this->CreateObject('lnkTicketToCI', $aData, $oChange);
  294. }
  295. // Change/Contact
  296. //
  297. $iInfraCount = rand(0, 6);
  298. for($iLinked = 0 ; $iLinked < $iInfraCount ; $iLinked++)
  299. {
  300. $aData = array(
  301. 'contact_id' => $this->RandomId('Person'),
  302. 'ticket_id' => $iTicket,
  303. 'role' => 'role '.$iLinked,
  304. );
  305. $this->CreateObject('lnkTicketToContact', $aData, $oChange);
  306. }
  307. }
  308. $this->MakeFeedback($oP, 'NormalChange');
  309. // 8 - Service calls
  310. //
  311. for($i = 0 ; $i < $this->m_aPlanned['ServiceCalls'] ; $i++)
  312. {
  313. $aData = array(
  314. 'org_id' => $iOrg,
  315. 'caller_id' => $this->RandomId('Person'),
  316. 'workgroup_id' => $this->RandomId('Team'),
  317. 'agent_id' => $this->RandomId('Person'),
  318. 'service_id' => $this->RandomId('Service'),
  319. 'servicesubcategory_id' => $this->RandomId('ServiceSubcategory'),
  320. 'title' => 'someevent'.$i,
  321. 'ticket_log' => 'Testing...',
  322. );
  323. $iTicket = $this->CreateObject('UserRequest', $aData, $oChange);
  324. // Call/Infra
  325. //
  326. $iInfraCount = rand(0, 6);
  327. for($iLinked = 0 ; $iLinked < $iInfraCount ; $iLinked++)
  328. {
  329. $aData = array(
  330. 'ci_id' => $this->RandomId('Server'),
  331. 'ticket_id' => $iTicket,
  332. );
  333. $this->CreateObject('lnkTicketToCI', $aData, $oChange);
  334. }
  335. }
  336. $this->MakeFeedback($oP, 'UserRequest');
  337. // 8 - Documents
  338. //
  339. $sMyDoc = '';
  340. for($i = 0 ; $i < 1000 ; $i++)
  341. {
  342. // 100 chars
  343. $sMyDoc .= "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678\n";
  344. }
  345. $oRefDoc = new ormDocument($sMyDoc, 'text/plain');
  346. for($i = 0 ; $i < $this->m_aPlanned['Documents'] ; $i++)
  347. {
  348. $aData = array(
  349. //'org_id' => $iOrg,
  350. 'name' => "document$i",
  351. 'contents' => $oRefDoc,
  352. );
  353. $this->CreateObject('FileDoc', $aData, $oChange);
  354. }
  355. $this->MakeFeedback($oP, 'FileDoc');
  356. }
  357. }
  358. /**
  359. * Ask the user what are the settings for the data load
  360. */
  361. function DisplayStep1(SetupWebPage $oP)
  362. {
  363. $sNextOperation = 'step2';
  364. $oP->add("<h1>iTop benchmarking</h1>\n");
  365. $oP->add("<h2>Please specify the requested volumes</h2>\n");
  366. $oP->add("<form method=\"post\" onSubmit=\"return DoSubmit('Evaluating real plans...', 10)\">\n");
  367. $oP->add("<fieldset><legend>Data load configuration</legend>\n");
  368. $aForm = array();
  369. $aForm[] = array(
  370. 'label' => "Main CIs:",
  371. 'input' => "<input id=\"to\" type=\"text\" name=\"plannedcis\" value=\"70\">",
  372. 'help' => ' exclude interfaces, subnets or any other type of secondary CI',
  373. );
  374. $aForm[] = array(
  375. 'label' => "Contacts:",
  376. 'input' => "<input id=\"from\" type=\"text\" name=\"plannedcontacts\" value=\"100\">",
  377. 'help' => '',
  378. );
  379. $aForm[] = array(
  380. 'label' => "Contracts:",
  381. 'input' => "<input id=\"from\" type=\"text\" name=\"plannedcontracts\" value=\"10\">",
  382. 'help' => '',
  383. );
  384. $oP->form($aForm);
  385. $oP->add("</fieldset>\n");
  386. $oP->add("<input type=\"hidden\" name=\"operation\" value=\"$sNextOperation\">\n");
  387. $oP->add("<button type=\"submit\">Next >></button>\n");
  388. $oP->add("</form>\n");
  389. }
  390. /**
  391. * Inform the user how many items will be created
  392. */
  393. function DisplayStep2(SetupWebPage $oP, $oDataCreation)
  394. {
  395. $sNextOperation = 'step3';
  396. $oP->add("<h1>iTop benchmarking</h1>\n");
  397. $oP->add("<h2>Step 2: review planned volumes</h2>\n");
  398. $aPlanned = $oDataCreation->GetPlan();
  399. $aForm = array();
  400. foreach ($aPlanned as $sKey => $iCount)
  401. {
  402. $aForm[] = array(
  403. 'label' => $sKey,
  404. 'input' => $iCount,
  405. );
  406. }
  407. $oP->form($aForm);
  408. $oP->add("<form method=\"post\" onSubmit=\"return DoSubmit('Loading data...', 10)\">\n");
  409. $oP->add("<input type=\"hidden\" name=\"operation\" value=\"$sNextOperation\">\n");
  410. $oP->add("<input type=\"hidden\" name=\"plannedcis\" value=\"".$aPlanned['CIs']."\">\n");
  411. $oP->add("<input type=\"hidden\" name=\"plannedcontacts\" value=\"".$aPlanned['Contacts']."\">\n");
  412. $oP->add("<input type=\"hidden\" name=\"plannedcontracts\" value=\"".$aPlanned['Contracts']."\">\n");
  413. $oP->add("<button type=\"submit\">Next >></button>\n");
  414. $oP->add("</form>\n");
  415. }
  416. /**
  417. * Do create the data set... could take some time to execute
  418. */
  419. function DisplayStep3(SetupWebPage $oP, $oDataCreation)
  420. {
  421. // $sNextOperation = 'step3';
  422. $oMyChange = MetaModel::NewObject("CMDBChange");
  423. $oMyChange->Set("date", time());
  424. $oMyChange->Set("userinfo", "Administrator");
  425. $iChangeId = $oMyChange->DBInsertNoReload();
  426. $oDataCreation->GoProjections($oP, $oMyChange);
  427. $oDataCreation->GoVolume($oP, $oMyChange);
  428. }
  429. /**
  430. * Main program
  431. */
  432. LoginWebPage::DoLogin(); // Check user rights and prompt if needed
  433. $sOperation = Utils::ReadParam('operation', 'step1');
  434. $oP = new SetupWebPage('iTop benchmark utility');
  435. try
  436. {
  437. switch($sOperation)
  438. {
  439. case 'step1':
  440. DisplayStep1($oP);
  441. break;
  442. case 'step2':
  443. $oP->no_cache();
  444. $iPlannedCIs = Utils::ReadParam('plannedcis');
  445. $iPlannedContacts = Utils::ReadParam('plannedcontacts');
  446. $iPlannedContracts = Utils::ReadParam('plannedcontracts');
  447. $oDataCreation = new BenchmarkDataCreation($iPlannedCIs, $iPlannedContacts, $iPlannedContracts);
  448. DisplayStep2($oP, $oDataCreation);
  449. break;
  450. case 'step3':
  451. $oP->no_cache();
  452. $iPlannedCIs = Utils::ReadParam('plannedcis');
  453. $iPlannedContacts = Utils::ReadParam('plannedcontacts');
  454. $iPlannedContracts = Utils::ReadParam('plannedcontracts');
  455. $oDataCreation = new BenchmarkDataCreation($iPlannedCIs, $iPlannedContacts, $iPlannedContracts);
  456. DisplayStep3($oP, $oDataCreation);
  457. break;
  458. default:
  459. $oP->error("Error: unsupported operation '$sOperation'");
  460. }
  461. }
  462. catch(ZZException $e)
  463. {
  464. $oP->error("Error: '".$e->getMessage()."'");
  465. }
  466. catch(ZZCoreException $e)
  467. {
  468. $oP->error("Error: '".$e->getHtmlDesc()."'");
  469. }
  470. $oP->output();
  471. ?>