|
|
|
แจก PHP Profiler สำหรับตรวจวัดว่าการทำงานของโค้ดเราเป็นยังไง ช้าตรงไหน ใช้หน่วยความจำเยอะตรงไหน |
|
|
|
|
|
|
|
ถ้าจะอ่านจากเว็บผมก็ได้นะ
จะดาวน์โหลดโดยตรงจาก Github repository ที่ผมทำแจกไว้ก็ได้เหมือนกัน.
จะเอาตัวอย่างโค้ดแบบสั้นๆก่อนละกัน กลัวมึน
Code (PHP)
// กรณีไม่ได้ติดตั้งผ่าน Composer จะต้อง require file ต่อไปนี้.
require 'Rundiz/Profiler/ProfilerBase.php';
require 'Rundiz/Profiler/Profiler.php';
// เริ่มคลาส profiler
$profiler = new \Rundiz\Profiler\Profiler();
$profiler->Console->registerLogSections(['Logs', 'Time Load']);
// ในส่วนของ registerLogSections จะมีทั้งหมดคือ 'Logs', 'Time Load', 'Memory Usage', 'Database', 'Files', 'Session', 'Get', 'Post' จะใส่เฉพาะบางอย่างก็ได้ ไม่ต้องใส่หมดก็ได้
// จากนั้นสามารถนำตัวแปร $profiler ไปใช้ได้ทันที
// Logs string, array, string+array
$profiler->Console->log('debug', 'Debug log or normal log data.');
$profiler->Console->log('info', ['Test' => 'Test log array data', 'Values' => 'Only have 1 level.']);
$profiler->Console->log('info', 'This is string. '."\n".print_r(['Test' => 'Test log array data', 'Values' => 'Only have 1 level.'], true));
// Time load
$profiler->Console->timeload('Time taken to this line.', __FILE__, __LINE__);
// กำหนด matchKey เพื่อให้ profiler คำณวนเวลาที่ใช้เฉพาะจุดในภายหลัง
$profiler->Console->timeload('Before usleep. Time taken to this line.', __FILE__, __LINE__, 'commontest_usleep');
usleep(100000);
$profiler->Console->timeload('After usleep. Time taken to this line.', __FILE__, __LINE__, 'commontest_usleep');
// Memory usage
$profiler->Console->memoryUsage('Memory usage to this line.', __FILE__, __LINE__);
// กำหนด matchKey เพื่อให้ profiler คำณวนหน่วยความจำที่ใช้เฉพาะจุดในภายหลัง
$profiler->Console->memoryUsage('Memory usage for this process.', __FILE__, __LINE__, 'imageprocessing');
// image processing source code here...
$profiler->Console->memoryUsage('Memory usage for this process.', __FILE__, __LINE__, 'imageprocessing');
// Database
$link = mysqli_connect('// bla bla bla กำหนด config เอาเองดิ');
$time_start = $profiler->getMicrotime();
$memory_start = memory_get_usage();
// sql statement
$sql = 'SELECT * FROM `table`';
$result = mysqli_query($link, $sql);
// ทำการเก็บข้อมูลเพื่อ profiling
$profiler->Console->database($sql, $time_start, $memory_start);
unset($memory_start, $time_start);
// ทำการแสดง query ไปตามปกติเหมือนที่คุณเคยทำมา
// แสดงผล profiler
// $link ได้มาจาก mysqli_connect();
echo $profiler->display($link, 'displayProfilerDb');
function displayProfilerDb(\Rundiz\Profiler\Profiler $profiler, $link, array $data_values)
{
// ดูด้านล่าง
}
ในส่วนของแสดงผล profiler ที่เป็น callback function สำหรับ mysqli มีรายละเอียดดังนี้.
Code (PHP)
function displayProfilerDb(\Rundiz\Profiler\Profiler $profiler, $link, array $data_values)
{
if (is_array($data_values)) {
if (array_key_exists('time_start', $data_values) && array_key_exists('time_end', $data_values)) {
echo '<div class="rdprofiler-log-db-timetake">'."\n";
echo $profiler->getReadableTime(($data_values['time_end']-$data_values['time_start'])*1000);
echo '</div>'."\n";
}
if (array_key_exists('memory_end', $data_values) && array_key_exists('memory_start', $data_values) && is_int($data_values['memory_end']) && is_int($data_values['memory_start'])) {
echo '<div class="rdprofiler-log-memory">';
echo $profiler->getReadableFileSize($data_values['memory_end']-$data_values['memory_start']);
echo '</div>'."\n";
}
}
if (strpos($data_values['data'], ';') !== false) {
// prevent sql injection! example: SELECT * FROM table where username = 'john'; DROP TABLE table;' this can execute 2 queries. explode them and just get the first!
$exp_data = explode(';', str_replace('; ', ';', $data_values['data']));
$data_values['data'] = $exp_data[0];
}
// use try ... catch to prevent any error by EXPLAIN. Example: EXPLAIN SHOW CHARACTER SET; <-- this will throw errors!
try {
$result = mysqli_query($link, 'EXPLAIN '.$data_values['data']);
if ($result) {
echo '<div class="rdprofiler-log-newrow">'."\n";
echo '<div class="rdprofiler-log-db-explain">'."\n";
if (isset($exp_data) && is_array($exp_data)) {
foreach ($exp_data as $key => $sqldata) {
if ($key != 0 && !empty($sqldata)) {
echo htmlspecialchars($sqldata, ENT_QUOTES).' cannot be explain due to it might be SQL injection!<br>'."\n";
}
}// endforeach;
unset($key, $sqldata);
}
$results = mysqli_fetch_all($result, MYSQLI_ASSOC);
if ($results) {
foreach ($results as $row) {
if (is_array($row) || is_object($row)) {
foreach ($row as $key => $val) {
echo $key . ' = ' . $val;
if (end($results) != $val) {
echo ', ';
}
}// endforeach;
}
echo '<br>'."\n";
}// endforeach;
}
unset($key, $results, $row, $val);
echo '</div>'."\n";
echo '</div>'."\n";
}
mysqli_free_result($result);
unset($result);
} catch (\Exception $ex) {
echo '<div class="rdprofiler-log-newrow">'."\n";
echo '<div class="rdprofiler-log-db-explain">'."\n";
echo '</div>'."\n";
echo '</div>'."\n";
}
if (is_array($data_values) && array_key_exists('call_trace', $data_values)) {
echo '<div class="rdprofiler-log-newrow">'."\n";
echo '<div class="rdprofiler-log-db-trace">'."\n";
echo '<strong>Call trace:</strong><br>'."\n";
foreach ($data_values['call_trace'] as $trace_item) {
echo $trace_item['file'].', line '.$trace_item['line'].'<br>'."\n";
}
unset($trace_item);
echo '</div>'."\n";
echo '</div>'."\n";
}
unset($exp_data);
}// displayProfilerDb
รูปต.ย.
มีภาพตัวอย่างอีกนะ อยู่ใน Github เปิดดูเอาสิ.
จริงๆโค้ดตัวนี้ทำแจกไว้นานมากแล้ว แต่ไม่ค่อยมีคนใช้ คงไม่มีคนรู้จัก หรือผมแนะนำวิธีใช้ไม่ละเอียดพอ เลยมานั่งเขียนใหม่เมื่อกี้หลังอัพเดทใหญ่ๆเมื่อวาน.
การทำ profiling ทำได้หลายวิธี ใช้ php profiler class, xdebug+cachegrind[+webgrind, qcachegrind], blackfire by symfony แต่ผมก็ใช้ทั้งตัวนี้และ xdebug ซึ่งผมมองว่า xdebug+webgrind มันแสดงเวลา self cost โดยไม่มีการรวมกับคำสั่งอื่นๆ เหมือนมันแยก self cost ของใครของมัน ผมต้องมานั่งคำณวนเอาเองอีกว่าตกลง method นี้มันใช้เวลาทั้งหมดเท่าไหร่กันแน่ ซึ่งมองว่าก็ไม่ค่อยสะดวก.
แต่ที่ผมทำออกมานี่ก็สะดวกพอสมควร สนองนี้ดตัวเองได้ในเบื้องต้น แต่ก็ทำงานช้ากว่า โดยเฉพาะโปรเจ็คบางตัวที่กำลังทำ พอเอา profiler ออกแล้วมันเร็วขึ้นราวๆ 200-400 milliseconds เลยทีเดียว ดังนั้นจึงไม่แนะนำให้พ่วงไปกับกระบวนการ production บน server จริง.
Tag : PHP
|
ประวัติการแก้ไข 2017-05-30 13:51:20 2017-05-30 13:56:51
|
|
|
|
|
Date :
2017-05-30 13:46:29 |
By :
mr.v |
View :
4980 |
Reply :
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ต้องลองซะแล้ว
|
|
|
|
|
Date :
2017-05-30 13:56:38 |
By :
POYKUB |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
เยี่ยมเบยครับ
|
|
|
|
|
Date :
2017-05-30 14:33:01 |
By :
mr.win |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Load balance : Server 01
|