diff --git a/src/applications/xhprof/controller/PhabricatorXHProfProfileController.php b/src/applications/xhprof/controller/PhabricatorXHProfProfileController.php index 9dbf1bd0be..15f6c47c66 100644 --- a/src/applications/xhprof/controller/PhabricatorXHProfProfileController.php +++ b/src/applications/xhprof/controller/PhabricatorXHProfProfileController.php @@ -1,53 +1,56 @@ phid = $data['phid']; } public function processRequest() { $request = $this->getRequest(); $file = id(new PhabricatorFileQuery()) ->setViewer($request->getUser()) ->withPHIDs(array($this->phid)) ->executeOne(); if (!$file) { return new Aphront404Response(); } $data = $file->loadFileData(); $data = @json_decode($data, true); if (!$data) { throw new Exception('Failed to unserialize XHProf profile!'); } $symbol = $request->getStr('symbol'); $is_framed = $request->getBool('frame'); if ($symbol) { $view = new PhabricatorXHProfProfileSymbolView(); $view->setSymbol($symbol); } else { $view = new PhabricatorXHProfProfileTopLevelView(); $view->setFile($file); $view->setLimit(100); } $view->setBaseURI($request->getRequestURI()->getPath()); $view->setIsFramed($is_framed); $view->setProfileData($data); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('%s Profile', $symbol)); + return $this->buildStandardPageResponse( - $view, + array($crumbs, $view), array( - 'title' => 'Profile', + 'title' => pht('Profile'), 'frame' => $is_framed, )); } } diff --git a/src/applications/xhprof/controller/PhabricatorXHProfSampleListController.php b/src/applications/xhprof/controller/PhabricatorXHProfSampleListController.php index 86f7221b8c..c96787cdf0 100644 --- a/src/applications/xhprof/controller/PhabricatorXHProfSampleListController.php +++ b/src/applications/xhprof/controller/PhabricatorXHProfSampleListController.php @@ -1,92 +1,95 @@ view = idx($data, 'view', 'all'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $pager = new AphrontPagerView(); $pager->setOffset($request->getInt('page')); switch ($this->view) { case 'sampled': $clause = '`sampleRate` > 0'; $show_type = false; break; case 'my-runs': $clause = qsprintf( id(new PhabricatorXHProfSample())->establishConnection('r'), '`sampleRate` = 0 AND `userPHID` = %s', $request->getUser()->getPHID()); $show_type = false; break; case 'manual': $clause = '`sampleRate` = 0'; $show_type = false; break; case 'all': default: $clause = '1 = 1'; $show_type = true; break; } $samples = id(new PhabricatorXHProfSample())->loadAllWhere( '%Q ORDER BY id DESC LIMIT %d, %d', $clause, $pager->getOffset(), $pager->getPageSize() + 1); $samples = $pager->sliceResults($samples); $pager->setURI($request->getRequestURI(), 'page'); $list = new PHUIObjectItemListView(); foreach ($samples as $sample) { $file_phid = $sample->getFilePHID(); $item = id(new PHUIObjectItemView()) ->setObjectName($sample->getID()) ->setHeader($sample->getRequestPath()) ->setHref($this->getApplicationURI('profile/'.$file_phid.'/')) ->addAttribute( number_format($sample->getUsTotal())." \xCE\xBCs"); if ($sample->getController()) { $item->addAttribute($sample->getController()); } $item->addAttribute($sample->getHostName()); $rate = $sample->getSampleRate(); if ($rate == 0) { $item->addIcon('flag-6', pht('Manual Run')); } else { $item->addIcon('flag-7', pht('Sampled (1/%d)', $rate)); } $item->addIcon( 'none', phabricator_datetime($sample->getDateCreated(), $user)); $list->addItem($item); } $list->setPager($pager); + $list->setNoDataString(pht('There are no profiling samples.')); - return $this->buildStandardPageResponse( - $list, + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('XHProf Samples')); + + return $this->buildApplicationPage( + array($crumbs, $list), array( 'title' => pht('XHProf Samples'), - 'device' => true, )); } } diff --git a/src/applications/xhprof/view/PhabricatorXHProfProfileSymbolView.php b/src/applications/xhprof/view/PhabricatorXHProfProfileSymbolView.php index e4f8ec94e6..5c37b0a8f8 100644 --- a/src/applications/xhprof/view/PhabricatorXHProfProfileSymbolView.php +++ b/src/applications/xhprof/view/PhabricatorXHProfProfileSymbolView.php @@ -1,134 +1,134 @@ profileData = $data; return $this; } public function setSymbol($symbol) { $this->symbol = $symbol; return $this; } public function render() { DarkConsoleXHProfPluginAPI::includeXHProfLib(); $data = $this->profileData; $GLOBALS['display_calls'] = true; $totals = array(); $flat = xhprof_compute_flat_info($data, $totals); unset($GLOBALS['display_calls']); $symbol = $this->symbol; $children = array(); $parents = array(); foreach ($this->profileData as $key => $counters) { if (strpos($key, '==>') !== false) { list($parent, $child) = explode('==>', $key, 2); } else { continue; } if ($parent == $symbol) { $children[$key] = $child; } else if ($child == $symbol) { $parents[$key] = $parent; } } $rows = array(); $rows[] = array( - 'Metrics for this Call', + pht('Metrics for this Call'), '', '', '', ); $rows[] = $this->formatRow( array( $symbol, $flat[$symbol]['ct'], $flat[$symbol]['wt'], 1.0, )); $rows[] = array( - 'Parent Calls', + pht('Parent Calls'), '', '', '', ); foreach ($parents as $key => $name) { $rows[] = $this->formatRow( array( $name, $data[$key]['ct'], $data[$key]['wt'], '', )); } $rows[] = array( - 'Child Calls', + pht('Child Calls'), '', '', '', ); $child_rows = array(); foreach ($children as $key => $name) { $child_rows[] = array( $name, $data[$key]['ct'], $data[$key]['wt'], $data[$key]['wt'] / $flat[$symbol]['wt'], ); } $child_rows = isort($child_rows, 2); $child_rows = array_reverse($child_rows); $rows = array_merge( $rows, array_map(array($this, 'formatRow'), $child_rows)); $table = new AphrontTableView($rows); $table->setHeaders( array( - 'Symbol', - 'Count', - 'Wall Time', + pht('Symbol'), + pht('Count'), + pht('Wall Time'), '%', )); $table->setColumnClasses( array( 'wide pri', 'n', 'n', 'n', )); - $panel = new AphrontPanelView(); - $panel->setHeader('XHProf Profile'); + $panel = new PHUIObjectBoxView(); + $panel->setHeader(pht('XHProf Profile')); $panel->appendChild($table); return $panel->render(); } private function formatRow(array $row) { return array( $this->renderSymbolLink($row[0]), number_format($row[1]), number_format($row[2]).' us', ($row[3] != '' ? sprintf('%.1f%%', 100 * $row[3]) : ''), ); } } diff --git a/src/applications/xhprof/view/PhabricatorXHProfProfileTopLevelView.php b/src/applications/xhprof/view/PhabricatorXHProfProfileTopLevelView.php index 12326bb16d..4fab88ec23 100644 --- a/src/applications/xhprof/view/PhabricatorXHProfProfileTopLevelView.php +++ b/src/applications/xhprof/view/PhabricatorXHProfProfileTopLevelView.php @@ -1,142 +1,143 @@ profileData = $data; return $this; } public function setLimit($limit) { $this->limit = $limit; return $this; } public function setFile(PhabricatorFile $file) { $this->file = $file; return $this; } public function render() { DarkConsoleXHProfPluginAPI::includeXHProfLib(); $GLOBALS['display_calls'] = true; $totals = array(); $flat = xhprof_compute_flat_info($this->profileData, $totals); unset($GLOBALS['display_calls']); $aggregated = array(); foreach ($flat as $call => $counters) { $parts = explode('@', $call, 2); $agg_call = reset($parts); if (empty($aggregated[$agg_call])) { $aggregated[$agg_call] = $counters; } else { foreach ($aggregated[$agg_call] as $key => $val) { if ($key != 'wt') { $aggregated[$agg_call][$key] += $counters[$key]; } } } } $flat = $aggregated; $flat = isort($flat, 'wt'); $flat = array_reverse($flat); $rows = array(); $rows[] = array( - 'Total', + pht('Total'), number_format($totals['ct']), number_format($totals['wt']).' us', '100.0%', number_format($totals['wt']).' us', '100.0%', ); if ($this->limit) { $flat = array_slice($flat, 0, $this->limit); } foreach ($flat as $call => $counters) { $rows[] = array( $this->renderSymbolLink($call), number_format($counters['ct']), number_format($counters['wt']).' us', sprintf('%.1f%%', 100 * $counters['wt'] / $totals['wt']), number_format($counters['excl_wt']).' us', sprintf('%.1f%%', 100 * $counters['excl_wt'] / $totals['wt']), ); } Javelin::initBehavior('phabricator-tooltips'); $table = new AphrontTableView($rows); $table->setHeaders( array( - 'Symbol', - 'Count', + pht('Symbol'), + pht('Count'), javelin_tag( 'span', array( 'sigil' => 'has-tooltip', 'meta' => array( - 'tip' => 'Total wall time spent in this function and all of '. + 'tip' => pht('Total wall time spent in this function and all of '. 'its children (children are other functions it called '. - 'while executing).', + 'while executing).'), 'size' => 200, ), ), 'Wall Time (Inclusive)'), '%', javelin_tag( 'span', array( 'sigil' => 'has-tooltip', 'meta' => array( - 'tip' => 'Wall time spent in this function, excluding time '. + 'tip' => pht('Wall time spent in this function, excluding time '. 'spent in children (children are other functions it '. - 'called while executing).', + 'called while executing).'), 'size' => 200, ), ), 'Wall Time (Exclusive)'), '%', )); $table->setColumnClasses( array( 'wide pri', 'n', 'n', 'n', 'n', 'n', )); - $panel = new AphrontPanelView(); - $panel->setHeader('XHProf Profile'); + $panel = new PHUIObjectBoxView(); + $header = id(new PHUIHeaderView()) + ->setHeaderText(pht('XHProf Profile')); if ($this->file) { - $panel->addButton( - phutil_tag( + $button = phutil_tag( 'a', array( 'href' => $this->file->getBestURI(), 'class' => 'green button', ), - 'Download .xhprof Profile')); + pht('Download .xhprof Profile')); + $header->addActionLink($button); } $panel->appendChild($table); return $panel->render(); } }