Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Benchmark w PHP, benchmark, ale nie profiler
q.michal
post 15.06.2017, 21:12:27
Post #1





Grupa: Zarejestrowani
Postów: 111
Pomógł: 1
Dołączył: 24.12.2013

Ostrzeżenie: (0%)
-----


Hello,

Dzis przedstawiam na szybko napisane 3 metody do testowania wydajnosci CPU, operacji I/O oraz bazy danych.
Kazda metoda zwraca przyznane punkty w formie INTa. Oczywiscie im wiecej tym lepiej.

Uwagi odnosnie tej jakze nikomu niepotrzebnej klasie jak zwykle mile widziane Lkingsmiley.png

Klasa:
  1. <?php
  2.  
  3. final class Benchmark {
  4.  
  5. /**
  6. * Benchmarks CPU and returns performance score
  7. *
  8. * @return integer CPU performance score
  9. */
  10. public static function getCPUScore() {
  11. $k = 0;
  12. $result = [];
  13. for($i = 0; $i < 25; $i++) {
  14. $start = System::getMiroTime();
  15. for($j = 0; $j < 1000000; $j++) {
  16. }
  17. $loop1 = System::getMiroTime() - $start;
  18. $start = System::getMiroTime();
  19. for($j = 0; $j < 1000000; $j++) {
  20. $k++;
  21. $k--;
  22. $k++;
  23. $k--;
  24. }
  25. $loop2 = System::getMiroTime() - $start;
  26. if ($loop2 > $loop1)
  27. $result[] = 1 / ($loop2 - $loop1);
  28. }
  29. if(count($result)) {
  30. return (int) round(array_sum($result) / doubleval(count($result)));
  31. } else {
  32. return 0;
  33. }
  34. }
  35.  
  36. /**
  37. * Benchmarks database and returns performance score
  38. *
  39. * @param object database object
  40. * @return integer database operations score
  41. * @throws exception if database connection or SQL query fails
  42. */
  43. public static function getDatabaseScore($database) {
  44. if(!is_a($database, 'Platform\\Database') || !$database->isConnected()) {
  45. throw new \Exception('No connection to database');
  46. }
  47. try {
  48. $database->setQuery('DELETE FROM #__performance');
  49. $database->execute();
  50. } catch(\PDOException $e) {
  51. throw new \Exception('Unable to truncate #__performance table');
  52. }
  53. $result = [];
  54. for($i = 0; $i < 25; $i++) {
  55. $start = System::getMiroTime();
  56. for($j = 0; $j < 10; $j++) {
  57. str_repeat('xyz', 66);
  58. }
  59. $loop1 = System::getMiroTime() - $start;
  60. $start = System::getMiroTime();
  61. for($j = 0; $j < 10; $j++) {
  62. try {
  63. $database->setQuery('INSERT INTO #__performance(ID, REF_ID, NAME) VALUES (?, ?, ?)');
  64. $database->execute([NULL, $j, str_repeat('xyz', 66)]);
  65. $database->setQuery('SELECT * FROM #__performance WHERE REF_ID = ?');
  66. $database->execute([$j]);
  67. $database->fetchRow();
  68. } catch(\PDOException $e) {
  69. throw new \Exception('Query execution failed during database benchmark');
  70. }
  71. }
  72. $loop2 = System::getMiroTime() - $start;
  73. if($loop2 > $loop1) {
  74. $result[] = 100 / ($loop2 - $loop1);
  75. }
  76. }
  77. if(count($result)) {
  78. return (int) round(array_sum($result) / doubleval(count($result)));
  79. } else {
  80. return 0;
  81. }
  82. }
  83.  
  84. /**
  85. * Benchmarks I/O operations and returns performance score
  86. *
  87. * @param string path to directory where temporary files necessary for test will be created
  88. * @return integer I/O operations performance score
  89. */
  90. public static function getIOScore($tempdir = '.') {
  91. $result = [];
  92. $testfile = $tempdir . '/io_benchmark_#N#.dat';
  93. $content = '<?php /*' . str_repeat('I/O Benchmark. ', 1024) . '*/ ?>';
  94. for($i = 0; $i < 25; $i++) {
  95. $start = System::getMiroTime();
  96. for($j = 0; $j < 1000; $j++) {
  97. str_replace("#N#", $j, $testfile);
  98. }
  99. $loop1 = System::getMiroTime() - $start;
  100. $start = System::getMiroTime();
  101. for($j = 0; $j < 1000; $j++) {
  102. $file = str_replace("#N#", $j, $testfile);
  103. file_put_contents($file, $content, LOCK_EX);
  104. require($file);
  105. unlink($file);
  106. }
  107. $loop2 = System::getMiroTime() - $start;
  108. if($loop2 > $loop1)
  109. $result[] = 1000 / ($loop2 - $loop1);
  110. }
  111. if(count($result)) {
  112. return (int) round(array_sum($result) / doubleval(count($result)));
  113. } else {
  114. return 0;
  115. }
  116. }
  117.  
  118. } /* class */


Przyklad uzycia:
  1. <?php
  2.  
  3. try {
  4. $database = \Platform\Database::getInstance();
  5. $database->connect('sqlite:tests/data/database.qdb', NULL, NULL, 'test_');
  6. $database->setQuery('CREATE TABLE IF NOT EXISTS #__performance(`ID` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `REF_ID` INTEGER DEFAULT NULL, `NAME` varchar(200) DEFAULT NULL)');
  7. $database->execute();
  8. }
  9. catch(\PDOException $e) {
  10. die('Something went wrong!');
  11. }
  12.  
  13. var_dump(\Platform\Benchmark::getCPUScore());
  14. var_dump(\Platform\Benchmark::getDatabaseScore($database));
  15. var_dump(\Platform\Benchmark::getIOScore('.'));


Wyniki:
Kod
int(187)
int(153)
int(1224)


Ten post edytował q.michal 16.06.2017, 15:04:39
Go to the top of the page
+Quote Post
nospor
post 16.06.2017, 10:07:13
Post #2





Grupa: Moderatorzy
Postów: 36 432
Pomógł: 6289
Dołączył: 27.12.2004




doubleval(count($result))

Naprawde uwazasz ze musisz zrzutowac liczbe calkowita do rzeczywistej by moc jej uzyc w dzieleniu?


Wyliczanie sredniej tak jak to robisz z procesow ktore dzialaja jeden po drugim w petli nie ma najmniejszego sensu

Ten caly SCORE rowniez jest do bani bo jest to poprostu "srednia" liczba sekund a nie zaden SCORE ktory moze cos znaczyc. Zmienisz kiedys liczbe iteracji i nagle SCORE bedzie totalnie inny


if(count($result)) {
return (int) round(array_sum($result) / doubleval(count($result)));
} else {
return 0;
}
Skoro $result wypelniasz w petli bez zadnych warunkow to naprawde myslisz ze kiedykolwiek moze to byc puste?


for($j = 0; $j < 1000; $j++) {
str_replace("#N#", $j, $testfile);
}
Nie wiem co ty tutaj testujesz ale na pewno nie IO


Generalnie patrzac na te twoje kolejne klasy to odnosze wrazenie ze zamiast isc do przodu, ty sie zwyczajnie cofasz.


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
Pyton_000
post 16.06.2017, 10:25:46
Post #3





Grupa: Zarejestrowani
Postów: 8 068
Pomógł: 1414
Dołączył: 26.10.2005

Ostrzeżenie: (0%)
-----


Ta pętla to chyba taka pozostałość do wywalenia smile.gif
Go to the top of the page
+Quote Post
nospor
post 16.06.2017, 10:28:07
Post #4





Grupa: Moderatorzy
Postów: 36 432
Pomógł: 6289
Dołączył: 27.12.2004




edit:
dobra, wracajac do tej $result to teraz dolukalem
if ($loop2 > $loop1)
$result[] = 1 / ($loop2 - $loop1);
Mozesz mi przyblizyc algorytm slownie?

@Pyton_000 no wlasnie chyba nie. To jakis wiekszy zamysl w jego algorytmie. Zauwasz, ze on wszedzie ma dwie petle, ta pierwsza z reguly szybsza, a potem odejmuje sobie czasy tych dwoch petli i dzieli w magiczny sposob. Jakis zamysl za tym jest wink.gif


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
Pyton_000
post 16.06.2017, 11:01:20
Post #5





Grupa: Zarejestrowani
Postów: 8 068
Pomógł: 1414
Dołączył: 26.10.2005

Ostrzeżenie: (0%)
-----


Tutaj powinny być oddzielne klasy dla każdego testu czyli IOBenchmark, DBBenchmark, CPUBenchmark, które dziedziczą po jakiejś klasie/interface typu IBenchmark.
Potem jakaś klasa do krórej pakujesz różne testy i odpalasz łącznie, do tego jeszcze klasa prezentera.

To taki chyba tylko wczesny draft smile.gif

W metodzie DB Benchmark powinno być typowanie parametru bo nie wiadomo co tam wrzucić jako parametr.

PS. A te pętle to chyba po to aby nie wliczać do score czasu działania samej pętli. taki myk biggrin.gif
Go to the top of the page
+Quote Post
nospor
post 16.06.2017, 11:54:39
Post #6





Grupa: Moderatorzy
Postów: 36 432
Pomógł: 6289
Dołączył: 27.12.2004




Cytat
PS. A te pętle to chyba po to aby nie wliczać do score czasu działania samej pętli. taki myk
Sprytne smile.gif


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
q.michal
post 16.06.2017, 11:55:27
Post #7





Grupa: Zarejestrowani
Postów: 111
Pomógł: 1
Dołączył: 24.12.2013

Ostrzeżenie: (0%)
-----


Tak, jest to taki draft, zawierajacy tylko metody wykonujace benchmark.
W 1 petli zliczam ile czasu zajmuje wykonanie samej petli + innych czynnosci nie zwiazanych np z samym I/O - tudziez wykonanie np str_repeat.
W 2 petli wykonuje to samo co w 1, plus dodatkowo zapisuje dane do pliku i odczytuje go, a nastepnie kasuje. Logiczne wydaje sie, ze ta 2 petla powinna dzialac dluzej, jednak nie moge tego zalozyc wprost - gdyz chociazby z uwagi na chwilowe obciazenie moze byc odwrotnie. Stad warunek "if ($loop2 > $loop1)". Caly test (w przypadku IO zapis, odczyt i usuniecie plikow - w sumie jest ich 1000) powtarzam 25x i wyciagam srednia.

Jak teraz na to patrze, ze rzeczywiscie doubleval wydaje sie zbedny.
Mam nadzieje ze ten kod az tak bardzo mnie nie uwstecznil biggrin.gif
Go to the top of the page
+Quote Post
markuz
post 16.06.2017, 12:18:33
Post #8





Grupa: Zarejestrowani
Postów: 1 240
Pomógł: 278
Dołączył: 11.03.2008

Ostrzeżenie: (0%)
-----


Wywal wszystko z static i napisz to od nowa.

Nazwy funkcji Ci podpowiadają, że coś trzeba wydzielić do osobnych klas tak jak pisał @Python_000:
getCPUScore
getDatabaseScore
getIOScore

Wolałem nie zagłębiać się w sens czy też praktycznie zastosowanie tej klasy - powyższe uwagi tylko do OOP. Teraz ta klasa jest klasą bo ma słówko class z przodu i tylko tyle ją łączy z OOP.


--------------------
Go to the top of the page
+Quote Post
q.michal
post 16.06.2017, 12:25:38
Post #9





Grupa: Zarejestrowani
Postów: 111
Pomógł: 1
Dołączył: 24.12.2013

Ostrzeżenie: (0%)
-----


Tak, wiem wink.gif
Skupilem sie wylacznie na funkcjonalnosci i jak napisalem w 1 poscie, jest to kod napisany na szybko.
Moze ktos znajdzie dla niego zastosowanie / natchnienie we wlasnym projekcie.


edit: Zauwazylem 'drobna literowke'. Drobna, bo zjadlem zero, a zmienia diametralnie wynik.
W linii 109 bylo:
$result[] = 100 / ($loop2 - $loop1);

a powinno byc:
$result[] = 1000 / ($loop2 - $loop1);

Ten post edytował q.michal 16.06.2017, 15:04:22
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 19.03.2024 - 11:33