Index: trunk/extensions/APC/APCImages.php |
— | — | @@ -0,0 +1,225 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class APCImages { |
| 5 | + |
| 6 | + const IMG_NONE = 0; |
| 7 | + const IMG_MEM_USAGE = 1; |
| 8 | + const IMG_HITS = 2; |
| 9 | + const IMG_FRAGMENTATION = 3; |
| 10 | + |
| 11 | + const GRAPH_SIZE = 200; |
| 12 | + |
| 13 | + // create graphics |
| 14 | + // |
| 15 | + public static function graphics_avail() { |
| 16 | + return extension_loaded('gd'); |
| 17 | + } |
| 18 | + |
| 19 | + public static function fill_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$color2,$text='',$placeindex=0) { |
| 20 | + $r=$diameter/2; |
| 21 | + $w=deg2rad((360+$start+($end-$start)/2)%360); |
| 22 | + |
| 23 | + |
| 24 | + if (function_exists("imagefilledarc")) { |
| 25 | + // exists only if GD 2.0.1 is avaliable |
| 26 | + imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, $start, $end, $color1, IMG_ARC_PIE); |
| 27 | + imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2, IMG_ARC_PIE); |
| 28 | + imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED); |
| 29 | + } else { |
| 30 | + imagearc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2); |
| 31 | + imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2); |
| 32 | + imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start+1)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2); |
| 33 | + imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end-1)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2); |
| 34 | + imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2); |
| 35 | + imagefill($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2, $color2); |
| 36 | + } |
| 37 | + if ($text) { |
| 38 | + if ($placeindex>0) { |
| 39 | + imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1); |
| 40 | + imagestring($im,4,$diameter, $placeindex*12,$text,$color1); |
| 41 | + |
| 42 | + } else { |
| 43 | + imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1); |
| 44 | + } |
| 45 | + } |
| 46 | + } |
| 47 | + |
| 48 | + public static function text_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$text,$placeindex=0) { |
| 49 | + $r=$diameter/2; |
| 50 | + $w=deg2rad((360+$start+($end-$start)/2)%360); |
| 51 | + |
| 52 | + if ($placeindex>0) { |
| 53 | + imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1); |
| 54 | + imagestring($im,4,$diameter, $placeindex*12,$text,$color1); |
| 55 | + |
| 56 | + } else { |
| 57 | + imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1); |
| 58 | + } |
| 59 | + } |
| 60 | + |
| 61 | + public static function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') { |
| 62 | + global $col_black; |
| 63 | + $x1=$x+$w-1; |
| 64 | + $y1=$y+$h-1; |
| 65 | + |
| 66 | + imagerectangle($im, $x, $y1, $x1+1, $y+1, $col_black); |
| 67 | + if($y1>$y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2); |
| 68 | + else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2); |
| 69 | + imagerectangle($im, $x, $y1, $x1, $y, $color1); |
| 70 | + if ($text) { |
| 71 | + if ($placeindex>0) { |
| 72 | + |
| 73 | + if ($placeindex<16) |
| 74 | + { |
| 75 | + $px=5; |
| 76 | + $py=$placeindex*12+6; |
| 77 | + imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2); |
| 78 | + imageline($im,$x,$y+$h/2,$px+90,$py,$color2); |
| 79 | + imagestring($im,2,$px,$py-6,$text,$color1); |
| 80 | + |
| 81 | + } else { |
| 82 | + if ($placeindex<31) { |
| 83 | + $px=$x+40*2; |
| 84 | + $py=($placeindex-15)*12+6; |
| 85 | + } else { |
| 86 | + $px=$x+40*2+100*intval(($placeindex-15)/15); |
| 87 | + $py=($placeindex%15)*12+6; |
| 88 | + } |
| 89 | + imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2); |
| 90 | + imageline($im,$x+$w,$y+$h/2,$px,$py,$color2); |
| 91 | + imagestring($im,2,$px+2,$py-6,$text,$color1); |
| 92 | + } |
| 93 | + } else { |
| 94 | + imagestring($im,4,$x+5,$y1-16,$text,$color1); |
| 95 | + } |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + public static function generateImage( $type ) { |
| 100 | + global $wgLang; |
| 101 | + |
| 102 | + $mem = apc_sma_info(); |
| 103 | + $cache = apc_cache_info( 'opcode' ); |
| 104 | + |
| 105 | + $size = self::GRAPH_SIZE; // image size |
| 106 | + if ($type==self::IMG_FRAGMENTATION) |
| 107 | + $image = imagecreate(2*$size+150, $size+10); |
| 108 | + else |
| 109 | + $image = imagecreate($size+10, $size+10); |
| 110 | + |
| 111 | + $col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF); |
| 112 | + $col_red = imagecolorallocate($image, 0xD0, 0x60, 0x30); |
| 113 | + $col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60); |
| 114 | + $col_black = imagecolorallocate($image, 0, 0, 0); |
| 115 | + imagecolortransparent($image,$col_white); |
| 116 | + |
| 117 | + switch ($type) { |
| 118 | + |
| 119 | + case 1: |
| 120 | + $s=$mem['num_seg']*$mem['seg_size']; |
| 121 | + $a=$mem['avail_mem']; |
| 122 | + $x=$y=$size/2; |
| 123 | + $fuzz = 0.000001; |
| 124 | + |
| 125 | + // This block of code creates the pie chart. It is a lot more complex than you |
| 126 | + // would expect because we try to visualize any memory fragmentation as well. |
| 127 | + $angle_from = 0; |
| 128 | + $string_placement=array(); |
| 129 | + for($i=0; $i<$mem['num_seg']; $i++) { |
| 130 | + $ptr = 0; |
| 131 | + $free = $mem['block_lists'][$i]; |
| 132 | + foreach($free as $block) { |
| 133 | + if($block['offset']!=$ptr) { // Used block |
| 134 | + $angle_to = $angle_from+($block['offset']-$ptr)/$s; |
| 135 | + if(($angle_to+$fuzz)>1) $angle_to = 1; |
| 136 | + self::fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red); |
| 137 | + if (($angle_to-$angle_from)>0.05) { |
| 138 | + array_push($string_placement, array($angle_from,$angle_to)); |
| 139 | + } |
| 140 | + $angle_from = $angle_to; |
| 141 | + } |
| 142 | + $angle_to = $angle_from+($block['size'])/$s; |
| 143 | + if(($angle_to+$fuzz)>1) $angle_to = 1; |
| 144 | + self::fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_green); |
| 145 | + if (($angle_to-$angle_from)>0.05) { |
| 146 | + array_push($string_placement, array($angle_from,$angle_to)); |
| 147 | + } |
| 148 | + $angle_from = $angle_to; |
| 149 | + $ptr = $block['offset']+$block['size']; |
| 150 | + } |
| 151 | + if ($ptr < $mem['seg_size']) { // memory at the end |
| 152 | + $angle_to = $angle_from + ($mem['seg_size'] - $ptr)/$s; |
| 153 | + if(($angle_to+$fuzz)>1) $angle_to = 1; |
| 154 | + self::fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red); |
| 155 | + if (($angle_to-$angle_from)>0.05) { |
| 156 | + array_push($string_placement, array($angle_from,$angle_to)); |
| 157 | + } |
| 158 | + } |
| 159 | + } |
| 160 | + foreach ($string_placement as $angle) { |
| 161 | + self::text_arc($image,$x,$y,$size,$angle[0]*360,$angle[1]*360,$col_black,$wgLang->formatSize($s*($angle[1]-$angle[0]))); |
| 162 | + } |
| 163 | + break; |
| 164 | + |
| 165 | + case 2: |
| 166 | + $s=$cache['num_hits']+$cache['num_misses']; |
| 167 | + $a=$cache['num_hits']; |
| 168 | + |
| 169 | + self::fill_box($image, 30,$size,50,-$a*($size-21)/$s,$col_black,$col_green,sprintf("%.1f%%",$cache['num_hits']*100/$s)); |
| 170 | + self::fill_box($image,130,$size,50,-max(4,($s-$a)*($size-21)/$s),$col_black,$col_red,sprintf("%.1f%%",$cache['num_misses']*100/$s)); |
| 171 | + break; |
| 172 | + |
| 173 | + case 3: |
| 174 | + $s=$mem['num_seg']*$mem['seg_size']; |
| 175 | + $a=$mem['avail_mem']; |
| 176 | + $x=130; |
| 177 | + $y=1; |
| 178 | + $j=1; |
| 179 | + |
| 180 | + // This block of code creates the bar chart. It is a lot more complex than you |
| 181 | + // would expect because we try to visualize any memory fragmentation as well. |
| 182 | + for($i=0; $i<$mem['num_seg']; $i++) { |
| 183 | + $ptr = 0; |
| 184 | + $free = $mem['block_lists'][$i]; |
| 185 | + foreach($free as $block) { |
| 186 | + if($block['offset']!=$ptr) { // Used block |
| 187 | + $h=(self::GRAPH_SIZE-5)*($block['offset']-$ptr)/$s; |
| 188 | + if ($h>0) { |
| 189 | + $j++; |
| 190 | + if($j<75) self::fill_box($image,$x,$y,50,$h,$col_black,$col_red,$wgLang->formatSize($block['offset']-$ptr),$j); |
| 191 | + else self::fill_box($image,$x,$y,50,$h,$col_black,$col_red); |
| 192 | + } |
| 193 | + $y+=$h; |
| 194 | + } |
| 195 | + $h=(self::GRAPH_SIZE-5)*($block['size'])/$s; |
| 196 | + if ($h>0) { |
| 197 | + $j++; |
| 198 | + if($j<75) self::fill_box($image,$x,$y,50,$h,$col_black,$col_green,$wgLang->formatSize($block['size']),$j); |
| 199 | + else self::fill_box($image,$x,$y,50,$h,$col_black,$col_green); |
| 200 | + } |
| 201 | + $y+=$h; |
| 202 | + $ptr = $block['offset']+$block['size']; |
| 203 | + } |
| 204 | + if ($ptr < $mem['seg_size']) { // memory at the end |
| 205 | + $h = (self::GRAPH_SIZE-5) * ($mem['seg_size'] - $ptr) / $s; |
| 206 | + if ($h > 0) { |
| 207 | + self::fill_box($image,$x,$y,50,$h,$col_black,$col_red,$wgLang->formatSize($mem['seg_size']-$ptr),$j++); |
| 208 | + } |
| 209 | + } |
| 210 | + } |
| 211 | + break; |
| 212 | + case 4: |
| 213 | + $s=$cache['num_hits']+$cache['num_misses']; |
| 214 | + $a=$cache['num_hits']; |
| 215 | + |
| 216 | + self::fill_box($image, 30,$size,50,-$a*($size-21)/$s,$col_black,$col_green,sprintf("%.1f%%",$cache['num_hits']*100/$s)); |
| 217 | + self::fill_box($image,130,$size,50,-max(4,($s-$a)*($size-21)/$s),$col_black,$col_red,sprintf("%.1f%%",$cache['num_misses']*100/$s)); |
| 218 | + break; |
| 219 | + |
| 220 | + } |
| 221 | + |
| 222 | + return imagepng( $image ); |
| 223 | + |
| 224 | + } |
| 225 | + |
| 226 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/APC/APCImages.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 227 | + native |
Index: trunk/extensions/APC/APCCacheMode.php |
— | — | @@ -0,0 +1,288 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class APCCacheMode { |
| 5 | + |
| 6 | + protected $opts, $title; |
| 7 | + |
| 8 | + protected $userMode = false; |
| 9 | + protected $fieldKey; |
| 10 | + |
| 11 | + public function __construct( FormOptions $opts, Title $title ) { |
| 12 | + $this->opts = $opts; |
| 13 | + $this->title = $title; |
| 14 | + $this->userMode = $opts->getValue( 'mode' ) === SpecialAPC::MODE_USER_CACHE; |
| 15 | + $this->fieldKey = $this->userMode ? 'info' : (ini_get('apc.stat') ? 'inode' : 'filename'); |
| 16 | + } |
| 17 | + |
| 18 | + protected $scopes = array( |
| 19 | + 'A' => 'cache_list', |
| 20 | + 'D' => 'deleted_list' |
| 21 | + ); |
| 22 | + |
| 23 | + protected function displayObject( $object ) { |
| 24 | + global $wgLang; |
| 25 | + |
| 26 | + $cache = apc_cache_info( $this->userMode ? 'user' : 'opcode' ); |
| 27 | + |
| 28 | + $s = |
| 29 | + Xml::openElement( 'div', array( 'class' => 'mw-apc-listing' ) ) . |
| 30 | + Xml::openElement( 'table' ) . Xml::openElement( 'tbody' ) . |
| 31 | + Xml::openElement( 'tr' ). |
| 32 | + Xml::element( 'th', null, wfMsg( 'viewapc-display-attribute' ) ) . |
| 33 | + Xml::element( 'th', null, wfMsg( 'viewapc-display-value' ) ) . |
| 34 | + Xml::closeElement( 'tr' ); |
| 35 | + |
| 36 | + $r = 1; |
| 37 | + foreach( $this->scopes as $list ) { |
| 38 | + foreach( $cache[$list] as $entry ) { |
| 39 | + if (md5($entry[$this->fieldKey]) !== $object) continue; |
| 40 | + |
| 41 | + foreach($entry as $key => $value) { |
| 42 | + $value = $this->formatValue( $key, $value ); |
| 43 | + switch ($key) { |
| 44 | + case 'num_hits': |
| 45 | + $value = $wgLang->formatNum( $value ) . |
| 46 | + $wgLang->formatNum( sprintf(" (%.2f%%)", $value*100/$cache['num_hits'] ) ); |
| 47 | + break; |
| 48 | + case 'deletion_time': |
| 49 | + if ( !$value ) { |
| 50 | + $value = wfMsg( 'viewapc-display-no-delete' ); |
| 51 | + break; |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + $s .= APCUtils::tableRow( $r=1-$r, |
| 56 | + wfMsgHtml( 'viewapc-display-' . $key ), |
| 57 | + htmlspecialchars( $value ) ); |
| 58 | + |
| 59 | + } |
| 60 | + |
| 61 | + if ( $this->userMode ) { |
| 62 | + $value = var_export(apc_fetch($entry[$this->fieldKey]),true); |
| 63 | + $s .= APCUtils::tableRow( $r=1-$r, |
| 64 | + wfMsgHtml( 'viewapc-display-stored-value' ), |
| 65 | + Xml::element( 'pre', null, $value ) ); |
| 66 | + } |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + $s .= '</tbody></table></div>'; |
| 71 | + return $s; |
| 72 | + } |
| 73 | + |
| 74 | + // sortable table header in "scripts for this host" view |
| 75 | + protected function sortHeader( $title, $overrides ) { |
| 76 | + $changed = $this->opts->getUnconsumedValues(); |
| 77 | + $target = $this->title->getLocalURL( wfArrayToCGI( $overrides, $changed ) ); |
| 78 | + return Xml::tags( 'a', array( 'href' => $target ), $title ); |
| 79 | + } |
| 80 | + |
| 81 | + protected function formatValue( $type, $value ) { |
| 82 | + global $wgLang; |
| 83 | + switch ( $type ) { |
| 84 | + case 'deletion_time': |
| 85 | + if ( !$value ) { |
| 86 | + $value = false; break; |
| 87 | + } |
| 88 | + case 'mtime': |
| 89 | + case 'creation_time': |
| 90 | + case 'access_time': |
| 91 | + $value = $wgLang->timeanddate( $value ); |
| 92 | + break; |
| 93 | + case 'ref_count': |
| 94 | + case 'num_hits': |
| 95 | + $value = $wgLang->formatNum( $value ); |
| 96 | + break; |
| 97 | + case 'mem_size': |
| 98 | + $value = $wgLang->formatSize( $value ); |
| 99 | + break; |
| 100 | + case 'ttl': |
| 101 | + $value = $wgLang->formatTimePeriod( $value ); |
| 102 | + break; |
| 103 | + case 'type': |
| 104 | + $value = wfMsg( 'viewapc-display-type-' . $value ); |
| 105 | + break; |
| 106 | + } |
| 107 | + return $value; |
| 108 | +} |
| 109 | + |
| 110 | + public function cacheView() { |
| 111 | + global $wgOut, $wgLang; |
| 112 | + |
| 113 | + $object = $this->opts->getValue( 'display' ); |
| 114 | + if ( $object ) { |
| 115 | + $wgOut->addHTML( $this->displayObject( $object ) ); |
| 116 | + return; |
| 117 | + } |
| 118 | + |
| 119 | + $wgOut->addHTML( $this->options() ); |
| 120 | + $wgOut->addHTML( '<div><table><tbody><tr>' ); |
| 121 | + |
| 122 | + $fields = array( 'name', 'hits', 'size', 'accessed', 'modified', 'created' ); |
| 123 | + if ( $this->userMode ) $fields[] = 'timeout'; |
| 124 | + $fields[] = 'deleted'; |
| 125 | + |
| 126 | + $fieldKeys = array( |
| 127 | + 'name' => $this->userMode ? 'info' : 'filename', |
| 128 | + 'hits' => 'num_hits', |
| 129 | + 'size' => 'mem_size', |
| 130 | + 'accessed' => 'access_time', |
| 131 | + 'modified' => 'mtime', |
| 132 | + 'created' => 'creation_time', |
| 133 | + 'timeout' => 'ttl', |
| 134 | + 'deleted' => 'deletion_time', |
| 135 | + ); |
| 136 | + |
| 137 | + $scope = $this->opts->getValue( 'scope' ); |
| 138 | + $sort = $this->opts->getValue( 'sort' ); |
| 139 | + $sortdir = $this->opts->getValue( 'sortdir' ); |
| 140 | + $limit = $this->opts->getValue( 'limit' ); |
| 141 | + $offset = $this->opts->getValue( 'offset' ); |
| 142 | + $search = $this->opts->getValue( 'searchi' ); |
| 143 | + |
| 144 | + foreach ( $fields as $field ) { |
| 145 | + $extra = array(); |
| 146 | + if ( $sort === $field ) { |
| 147 | + $extra = array( 'sortdir' => 1-$sortdir ); |
| 148 | + } |
| 149 | + |
| 150 | + $wgOut->addHTML( |
| 151 | + Xml::tags( 'th', null, $this->sortHeader( |
| 152 | + wfMsgHtml( 'viewapc-ls-header-' . $field ), |
| 153 | + array( 'sort' => $field ) + $extra ) ) |
| 154 | + ); |
| 155 | + } |
| 156 | + |
| 157 | + $wgOut->addHTML( '</tr>' ); |
| 158 | + |
| 159 | + $cache = apc_cache_info( $this->userMode ? 'user' : 'opcode' ); |
| 160 | + $list = array(); |
| 161 | + if ( $scope === 'active' || $scope === 'both' ) { |
| 162 | + foreach ( $cache['cache_list'] as $entry ) { |
| 163 | + if ( $search && stripos( $entry[$fieldKeys['name']], $search ) === false ) continue; |
| 164 | + $sortValue = sprintf('%015d-', $entry[$fieldKeys[$sort]]); |
| 165 | + $list[$sortValue . $entry[$fieldKeys['name']]] = $entry; |
| 166 | + } |
| 167 | + } |
| 168 | + |
| 169 | + if ( $scope === 'deleted' || $scope === 'both' ) { |
| 170 | + foreach ( $cache['deleted_list'] as $entry ) { |
| 171 | + if ( $search && stripos( $entry[$fieldKeys['name']], $search ) === false ) continue; |
| 172 | + $sortValue = sprintf('%015d-', $entry[$fieldKeys[$sort]]); |
| 173 | + $list[$sortValue . $entry[$fieldKeys['name']]] = $entry; |
| 174 | + } |
| 175 | + } |
| 176 | + |
| 177 | + $sortdir ? krsort( $list ) : ksort( $list ); |
| 178 | + |
| 179 | + $i = 0; |
| 180 | + if ( count($list) ) { |
| 181 | + $r = 1; |
| 182 | + |
| 183 | + foreach ( $list as $name => $entry ) { |
| 184 | + if ( $limit === $i++ ) break; |
| 185 | + $wgOut->addHTML( |
| 186 | + Xml::openElement( 'tr', array( 'class' => 'mw-apc-tr-' . ($r=1-$r) ) ) |
| 187 | + ); |
| 188 | + |
| 189 | + foreach ( $fields as $field ) { |
| 190 | + $index = $fieldKeys[$field]; |
| 191 | + if ( $field === 'name' ) { |
| 192 | + if ( !$this->userMode ) { |
| 193 | + $pos = strrpos( $entry[$index], '/' ); |
| 194 | + if ( $pos !== false ) $value = substr( $entry[$index], $pos+1 ); |
| 195 | + } else { |
| 196 | + $value = $entry[$index]; |
| 197 | + } |
| 198 | + $value = $this->sortHeader( htmlspecialchars($value), array( 'display' => md5($entry[$this->fieldKey]) ) ); |
| 199 | + } elseif( $field === 'deleted' && $this->userMode && !$entry[$index] ) { |
| 200 | + $value = $this->sortHeader( |
| 201 | + wfMsgHtml( 'viewapc-ls-delete' ), |
| 202 | + array( 'delete' => $entry[$this->fieldKey] ) |
| 203 | + ); |
| 204 | + } else { |
| 205 | + $value = $this->formatValue( $index, $entry[$index] ); |
| 206 | + } |
| 207 | + |
| 208 | + $wgOut->addHTML( Xml::tags( 'td', null, $value ) ); |
| 209 | + } |
| 210 | + |
| 211 | + $wgOut->addHTML( '</tr>' ); |
| 212 | + } |
| 213 | + } |
| 214 | + |
| 215 | + if ( $i < count($list) ) { |
| 216 | + $left = $wgLang->formatNum( count($list) - ($i+$offset) ); |
| 217 | + $wgOut->addHTML( |
| 218 | + Xml::tags( 'tr', array( 'colspan' => count( $fields ) ), |
| 219 | + Xml::tags( 'td', null, $this->sortHeader( |
| 220 | + wfMsgExt( 'viewapc-ls-more', 'parseinline', $left ), |
| 221 | + array( 'offset' => $offset+$limit ) ) ) ) |
| 222 | + ); |
| 223 | + } elseif ( !count($list) ) { |
| 224 | + $wgOut->addHTML( |
| 225 | + Xml::tags( 'tr', array( 'colspan' => count( $fields ) ), |
| 226 | + Xml::tags( 'td', null, wfMsgExt( 'viewapc-ls-nodata', 'parseinline' ) ) ) |
| 227 | + ); |
| 228 | + } |
| 229 | + |
| 230 | + $wgOut->addHTML( '</tbody></table></div>' ); |
| 231 | + } |
| 232 | + |
| 233 | + protected function options() { |
| 234 | + global $wgLang; |
| 235 | + |
| 236 | + $s = |
| 237 | + Xml::openElement( 'fieldset' ) . |
| 238 | + Xml::element( 'legend', null, wfMsg( 'viewapc-ls-options-legend' ) ) . |
| 239 | + Xml::openElement( 'form', array( 'action' => $this->title->getLocalURl() ) ); |
| 240 | + |
| 241 | + foreach ( $this->opts->getUnconsumedValues() as $key => $value ) { |
| 242 | + $s .= Xml::hidden( $key, $value ); |
| 243 | + } |
| 244 | + |
| 245 | + $options = array(); |
| 246 | + $scope = $this->opts->consumeValue( 'scope' ); |
| 247 | + $scopeOptions = array( 'active', 'deleted', 'both' ); |
| 248 | + foreach ( $scopeOptions as $name ) { |
| 249 | + $options[] = Xml::option( wfMsg( 'viewapc-ls-scope-' . $name ), $name, $scope === $name ); |
| 250 | + } |
| 251 | + $scopeSelector = Xml::tags( 'select', array( 'name' => 'scope' ), implode( "\n", $options ) ); |
| 252 | + |
| 253 | + $options = array(); |
| 254 | + $sort = $this->opts->consumeValue( 'sort' ); |
| 255 | + $sortOptions = array( 'hits', 'size', 'name', 'accessed', 'modified', 'created', 'deleted' ); |
| 256 | + if ( $this->userMode ) $sortOptions[] = 'timeout'; |
| 257 | + foreach ( $sortOptions as $name ) { |
| 258 | + $options[] = Xml::option( wfMsg( 'viewapc-ls-sort-' . $name ), $name, $sort === $name ); |
| 259 | + } |
| 260 | + $sortSelector = Xml::tags( 'select', array( 'name' => 'sort' ), implode( "\n", $options ) ); |
| 261 | + |
| 262 | + $options = array(); |
| 263 | + $sortdir = $this->opts->consumeValue( 'sortdir' ); |
| 264 | + $options[] = Xml::option( wfMsg( 'ascending_abbrev' ), 0, !$sortdir ); |
| 265 | + $options[] = Xml::option( wfMsg( 'descending_abbrev' ), 1, $sortdir ); |
| 266 | + $sortdirSelector = Xml::tags( 'select', array( 'name' => 'sortdir' ), implode( "\n", $options ) ); |
| 267 | + |
| 268 | + |
| 269 | + $options = array(); |
| 270 | + $limit = $this->opts->consumeValue( 'limit' ); |
| 271 | + $limitOptions = array( 10, 20, 50, 150, 200, 500, $limit ); |
| 272 | + sort( $limitOptions ); |
| 273 | + foreach ( $limitOptions as $name ) { |
| 274 | + $options[] = Xml::option( $wgLang->formatNum( $name ), $name, $limit === $name ); |
| 275 | + } |
| 276 | + $options[] = Xml::option( wfMsg( 'viewapc-ls-limit-none' ), 0, $limit === $name ); |
| 277 | + $limitSelector = Xml::tags( 'select', array( 'name' => 'limit' ), implode( "\n", $options ) ); |
| 278 | + |
| 279 | + |
| 280 | + $searchBox = Xml::input( 'searchi', 25, $this->opts->getValue( 'searchi' ) ); |
| 281 | + $submit = Xml::submitButton( wfMsg( 'viewapc-ls-submit' ) ); |
| 282 | + |
| 283 | + $s .= wfMsgHtml( 'viewapc-ls-options', $scopeSelector, $sortSelector, |
| 284 | + $sortdirSelector, $limitSelector, $searchBox, $submit ); |
| 285 | + $s .= '</form></fieldset><br />'; |
| 286 | + |
| 287 | + return $s; |
| 288 | + } |
| 289 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/APC/APCCacheMode.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 290 | + native |
Index: trunk/extensions/APC/ViewAPC.i18n.php |
— | — | @@ -0,0 +1,128 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +$messages = array(); |
| 5 | + |
| 6 | +$messages['en'] = array( |
| 7 | +'viewapc' => 'APC information', |
| 8 | +'viewapc-desc' => 'View and manage APC cache with MediaWiki', |
| 9 | +'right-apc' => 'Use all features in Special:APC', |
| 10 | + |
| 11 | +'viewapc-apc-not-available' => 'No cache info available. APC does not appear to be running.', |
| 12 | +'viewapc-clear-confirm' => 'Do you want to clear the cache?', |
| 13 | +'viewapc-clear-user-cache' => 'Clear user cache', |
| 14 | +'viewapc-clear-code-cache' => 'Clear opcode cache', |
| 15 | + |
| 16 | +'viewapc-mode-stats' => 'View host stats', |
| 17 | +'viewapc-mode-system-cache' => 'System cache entries', |
| 18 | +'viewapc-mode-system-cache-dir' => 'Per-directory entries', |
| 19 | +'viewapc-mode-user-cache' => 'User cache entries', |
| 20 | +'viewapc-mode-version-check' => 'Check version', |
| 21 | + |
| 22 | +'viewapc-info-general' => 'General information', |
| 23 | +'viewapc-apc-version' => 'APC version', |
| 24 | +'viewapc-php-version' => 'PHP version', |
| 25 | +'viewapc-shared-memory' => 'Shared memory', |
| 26 | +'viewapc-shared-memory-details' => '{{PLURAL:$1|1 segment of $2|$1 segments $2 each}}.<br /> |
| 27 | +($3 memory, $4 locking)', |
| 28 | +'viewapc-start-time' => 'Start time', |
| 29 | +'viewapc-uptime' => 'Uptime', |
| 30 | +'viewapc-upload-support' => 'File upload support', |
| 31 | + |
| 32 | +'viewapc-filecache-info' => 'File cache information', |
| 33 | +'viewapc-usercache-info' => 'User cache information', |
| 34 | +'viewapc-cached-files' => 'Cached files', |
| 35 | +'viewapc-cached-files-d' => '$1 {{PLURAL:$1|file|files}} ($2)', |
| 36 | +'viewapc-hits' => 'Hits', |
| 37 | +'viewapc-misses' => 'Misses', |
| 38 | +'viewapc-requests' => 'Request rate', |
| 39 | +'viewapc-hitrate' => 'Hit rate', |
| 40 | +'viewapc-missrate' => 'Miss rate', |
| 41 | +'viewapc-insertrate' => 'Insertion rate', |
| 42 | +'viewapc-cachefull' => 'Cache full count', |
| 43 | +'viewapc-rps' => '$1 requests per second', |
| 44 | + |
| 45 | +'viewapc-info-runtime' => 'Runtime information', |
| 46 | + |
| 47 | +'viewapc-info-memory' => 'Host status diagrams', |
| 48 | +'viewapc-memory-usage-detailed' => 'Memory Usage<br /> |
| 49 | +(multiple slices indicate fragments)', |
| 50 | +'viewapc-memory-usage' => 'Memory Usage', |
| 51 | +'viewapc-cache-efficiency' => 'Hits and misses', |
| 52 | + |
| 53 | +'viewapc-memory-free' => 'Free: $1 ($2)', |
| 54 | +'viewapc-memory-used' => 'Used: $1 ($2)', |
| 55 | +'viewapc-memory-hits' => 'Hits: $1 ($2)', |
| 56 | +'viewapc-memory-miss' => 'Misses: $1 ($2)', |
| 57 | + |
| 58 | +'viewapc-memoryfragmentation' => 'Detailed memory usage and fragmentation', |
| 59 | +'viewapc-fragmentation-info' => 'Fragmentation: $1 ($2 out of $3 in $4 {{PLURAL:$4|fragment|fragments}})', |
| 60 | +'viewapc-fragmentation-none' => 'Fragmentation: no fragmentation', |
| 61 | + |
| 62 | +'viewapc-display-attribute' => 'Attribute', |
| 63 | +'viewapc-display-value' => 'Value', |
| 64 | + |
| 65 | +'viewapc-display-filename' => 'Filename', |
| 66 | +'viewapc-display-device' => 'Device', |
| 67 | +'viewapc-display-info' => 'Name', |
| 68 | +'viewapc-display-ttl' => 'Expiry time', |
| 69 | +'viewapc-display-inode' => 'Inode', |
| 70 | +'viewapc-display-type' => 'Type', |
| 71 | +'viewapc-display-type-file' => 'Cached file', |
| 72 | +'viewapc-display-type-user' => 'Cached application data', |
| 73 | +'viewapc-display-num_hits' => 'Hits', |
| 74 | +'viewapc-display-mtime' => 'Modified', |
| 75 | +'viewapc-display-creation_time' => 'Created', |
| 76 | +'viewapc-display-deletion_time' => 'Deleted', |
| 77 | +'viewapc-display-no-delete' => 'Not deleted', |
| 78 | +'viewapc-display-access_time' => 'Accessed', |
| 79 | +'viewapc-display-ref_count' => 'Reference count', |
| 80 | +'viewapc-display-mem_size' => 'Size', |
| 81 | +'viewapc-display-stored-value' => 'Stored value', |
| 82 | + |
| 83 | +'viewapc-ls-options-legend' => 'Options', |
| 84 | +'viewapc-ls-options' => 'Scope: $1 Sorting: $2$3$4 Search: $5 $6', |
| 85 | +'viewapc-ls-submit' => 'Go!', |
| 86 | + |
| 87 | +'viewapc-ls-header-name' => 'Name', |
| 88 | +'viewapc-ls-header-hits' => 'Hits', |
| 89 | +'viewapc-ls-header-size' => 'Size', |
| 90 | +'viewapc-ls-header-accessed' => 'Last accessed', |
| 91 | +'viewapc-ls-header-modified' => 'Last modified', |
| 92 | +'viewapc-ls-header-created' => 'Created', |
| 93 | +'viewapc-ls-header-deleted' => 'Deleted', |
| 94 | +'viewapc-ls-header-timeout' => 'Timeout', |
| 95 | + |
| 96 | +'viewapc-ls-delete' => '[Delete now]', |
| 97 | + |
| 98 | +'viewapc-ls-scope-active' => 'Active', |
| 99 | +'viewapc-ls-scope-deleted' => 'Deleted', |
| 100 | +'viewapc-ls-scope-both' => 'Both', |
| 101 | + |
| 102 | + |
| 103 | +'viewapc-ls-sort-hits' => 'Hits', |
| 104 | +'viewapc-ls-sort-size' => 'Size', |
| 105 | +'viewapc-ls-sort-name' => 'Name', |
| 106 | +'viewapc-ls-sort-accessed' => 'Last accessed', |
| 107 | +'viewapc-ls-sort-modified' => 'Last modified', |
| 108 | +'viewapc-ls-sort-created' => 'Created', |
| 109 | +'viewapc-ls-sort-deleted' => 'Deleted', |
| 110 | +'viewapc-ls-sort-timeout' => 'Timeout', |
| 111 | + |
| 112 | +'viewapc-ls-limit-none' => 'All', |
| 113 | +'viewapc-ls-more' => "''There is $1 more {{PLURAL:$1|entry|entries}}''", |
| 114 | +'viewapc-ls-nodata' => "''No matching data''", |
| 115 | + |
| 116 | +'viewapc-delete-ok' => 'Cache entry <nowiki>$1</nowiki> is deleted.', |
| 117 | +'viewapc-delete-failed' => 'Failed to delete cache entry <nowiki>$1</nowiki>.', |
| 118 | + |
| 119 | +'viewapc-version-info' => 'Version information', |
| 120 | +'viewapc-version-changelog' => 'Changelog', |
| 121 | +'viewapc-version-failed' => 'Unable to fetch version information.', |
| 122 | +'viewapc-version-ok' => 'You are running the latest version of APC ($1)', |
| 123 | +'viewapc-version-old' => 'You are running an older version of APC ($1). |
| 124 | +Newer version $2 is available at http://pecl.php.net/package/APC/$2', |
| 125 | + |
| 126 | +'viewapc-filecache-cleared' => "'''''File cache cleared.'''''", |
| 127 | +'viewapc-usercache-cleared' => "'''''Application cache cleared.'''''", |
| 128 | + |
| 129 | +); |
Property changes on: trunk/extensions/APC/ViewAPC.i18n.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 130 | + native |
Index: trunk/extensions/APC/ViewAPC.php |
— | — | @@ -0,0 +1,32 @@ |
| 2 | +<?php |
| 3 | +if (!defined('MEDIAWIKI')) die(); |
| 4 | +/** |
| 5 | + * An extension to allow access to APC status with MediaWiki rights |
| 6 | + * |
| 7 | + * @addtogroup Extensions |
| 8 | + * |
| 9 | + * @author Niklas Laxström |
| 10 | + * @copyright Copyright © 2008, Niklas Laxström |
| 11 | + */ |
| 12 | + |
| 13 | + |
| 14 | +$wgExtensionCredits['specialpage'][] = array( |
| 15 | + 'name' => 'Apc', |
| 16 | + 'version' => '2008-05-04', |
| 17 | + 'author' => 'Niklas Laxström', |
| 18 | + 'description' => '[[Special:ViewAPC|Special page]] for viewing memory cache', |
| 19 | + 'descriptionmsg' => 'viewapc-desc', |
| 20 | +); |
| 21 | + |
| 22 | +$dir = dirname(__FILE__) . '/'; |
| 23 | +$wgAutoloadClasses['SpecialAPC'] = $dir . 'SpecialAPC.php'; |
| 24 | +$wgAutoloadClasses['APCImages'] = $dir . 'APCImages.php'; |
| 25 | +$wgAutoloadClasses['APCUtils'] = $dir . 'APCUtils.php'; |
| 26 | + |
| 27 | +$wgAutoloadClasses['APCHostMode'] = $dir . 'APCHostMode.php'; |
| 28 | +$wgAutoloadClasses['APCCacheMode'] = $dir . 'APCCacheMode.php'; |
| 29 | + |
| 30 | +$wgExtensionMessagesFiles['ViewAPC'] = $dir . 'ViewAPC.i18n.php'; |
| 31 | +$wgSpecialPages['ViewAPC'] = 'SpecialAPC'; |
| 32 | + |
| 33 | +$wgAvailableRights[] = 'apc'; |
Property changes on: trunk/extensions/APC/ViewAPC.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 34 | + native |
Index: trunk/extensions/APC/APCUtils.php |
— | — | @@ -0,0 +1,31 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class APCUtils { |
| 5 | + |
| 6 | + public static function tableRow( $class, $first, $second = null ) { |
| 7 | + $class = $class !== null ? array( 'class' => 'mw-apc-tr-' . $class ) : null; |
| 8 | + |
| 9 | + return Xml::tags( 'tr', $class, |
| 10 | + Xml::tags( 'td', array( 'class' => 'mw-apc-td-0' ), $first ) . |
| 11 | + Xml::tags( 'td', null, $second ) ); |
| 12 | + } |
| 13 | + |
| 14 | + public static function tableHeader( $header, $class = '' ) { |
| 15 | + return |
| 16 | + Xml::openElement( 'div', array( 'class' => "mw-apc-stats $class" ) ) . |
| 17 | + Xml::element( 'h2', null, $header ) . |
| 18 | + Xml::openElement( 'table' ) . |
| 19 | + Xml::openElement( 'tbody' ); |
| 20 | + } |
| 21 | + |
| 22 | + public static function tableFooter() { |
| 23 | + return "</tbody></table></div>"; |
| 24 | + } |
| 25 | + |
| 26 | + public static function formatReqPerS( $number ) { |
| 27 | + global $wgLang; |
| 28 | + return wfMsgExt( 'viewapc-rps', 'parsemag', |
| 29 | + $wgLang->formatNum( sprintf("%.2f", $number ), true ) ); |
| 30 | + } |
| 31 | + |
| 32 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/APC/APCUtils.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 33 | + native |
Index: trunk/extensions/APC/SpecialAPC.php |
— | — | @@ -0,0 +1,269 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class SpecialAPC extends SpecialPage { |
| 5 | + |
| 6 | + const GRAPH_SIZE = 200; |
| 7 | + |
| 8 | + // Stored objects |
| 9 | + |
| 10 | + protected $opts, $title; |
| 11 | + function __construct() { |
| 12 | + SpecialPage::SpecialPage( 'ViewAPC' ); |
| 13 | + $this->title = $this->getTitle(); |
| 14 | + } |
| 15 | + |
| 16 | + const MODE_STATS = 0; |
| 17 | + const MODE_SYSTEM_CACHE = 1; |
| 18 | + const MODE_USER_CACHE = 2; |
| 19 | + const MODE_SYSTEM_CACHE_DIR = 3; |
| 20 | + const MODE_VERSION_CHECK = 4; |
| 21 | + |
| 22 | + public function setup() { |
| 23 | + global $wgRequest; |
| 24 | + |
| 25 | + $opts = new FormOptions(); |
| 26 | + // Bind to the member variable |
| 27 | + $this->opts = $opts; |
| 28 | + |
| 29 | + |
| 30 | + $opts->add( 'mode', self::MODE_STATS ); |
| 31 | + $opts->add( 'image', APCImages::IMG_NONE ); |
| 32 | + $opts->add( 'clearcache', false ); |
| 33 | + $opts->add( 'limit', 20 ); |
| 34 | + $opts->add( 'offset', 0 ); |
| 35 | + $opts->add( 'display', '' ); |
| 36 | + $opts->add( 'delete', '' ); |
| 37 | + $opts->add( 'sort', 'hits' ); |
| 38 | + $opts->add( 'sortdir', 0 ); |
| 39 | + $opts->add( 'scope', 'active' ); |
| 40 | + $opts->add( 'searchi', ''); // MediaWiki captures search, ARGH! |
| 41 | + |
| 42 | + $opts->fetchValuesFromRequest( $wgRequest ); |
| 43 | + $opts->validateIntBounds( 'limit', 0, 5000 ); |
| 44 | + $opts->validateIntBounds( 'sortdir', 0, 1 ); |
| 45 | + $this->opts->consumeValues( array( 'display', 'clearcache', 'image' ) ); |
| 46 | + |
| 47 | + } |
| 48 | + |
| 49 | + public function execute( $parameters ) { |
| 50 | + global $wgOut, $wgScriptPath, $wgStyleVersion, $wgUser; |
| 51 | + wfLoadExtensionMessages( 'ViewAPC' ); |
| 52 | + $this->setHeaders(); |
| 53 | + $this->setup(); |
| 54 | + |
| 55 | + |
| 56 | + if( !function_exists('apc_cache_info')) { |
| 57 | + $wgOut->addWikiMsg( 'viewapc-apc-not-available' ); |
| 58 | + return; |
| 59 | + } |
| 60 | + |
| 61 | + if ( $this->opts->getValue('image') ) { |
| 62 | + $wgOut->disable(); |
| 63 | + header('Content-type: image/png'); |
| 64 | + echo APCImages::generateImage( $this->opts->getValue('image') ); |
| 65 | + return; |
| 66 | + } |
| 67 | + |
| 68 | + if ( $this->opts->getValue('mode') !== self::MODE_STATS ) { |
| 69 | + if ( !$wgUser->isAllowed( 'apc' ) ) { |
| 70 | + $wgOut->permissionRequired( 'apc' ); |
| 71 | + return; |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + |
| 76 | + |
| 77 | + // clear cache |
| 78 | + if ( $this->opts->consumeValue( 'clearcache' ) ) { |
| 79 | + $usermode = $this->opts->getValue( 'mode' ) === self::MODE_USER_CACHE; |
| 80 | + $mode = $usermode ? 'user' : 'opcode'; |
| 81 | + apc_clear_cache( $mode ); |
| 82 | + if ( $usermode ) { |
| 83 | + $wgOut->addWikiMsg( 'viewapc-filecache-cleared' ); |
| 84 | + } else { |
| 85 | + $wgOut->addWikiMsg( 'viewapc-usercache-cleared' ); |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + $delete = $this->opts->consumeValue( 'delete' ); |
| 90 | + if ( $delete ) { |
| 91 | + $result = apc_delete( $delete ); |
| 92 | + if ( $result ) { |
| 93 | + $wgOut->addWikiMsg( 'viewapc-delete-ok', $delete ); |
| 94 | + } else { |
| 95 | + $wgOut->addWikiMsg( 'viewapc-delete-failed', $delete ); |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + |
| 100 | + $dir = dirname( __FILE__ ); |
| 101 | + $wgOut->addLink( array( 'rel' => 'stylesheet', 'type' => 'text/css', |
| 102 | + 'href' => "$wgScriptPath/extensions/APC/apc.css?$wgStyleVersion", ) |
| 103 | + ); |
| 104 | + |
| 105 | + $this->getLogo(); |
| 106 | + $this->mainMenu(); |
| 107 | + $this->doPage(); |
| 108 | + } |
| 109 | + |
| 110 | + protected function selfLink( $parms, $name, $attribs = array() ) { |
| 111 | + $title = $this->getTitle(); |
| 112 | + $target = $title->getLocalURL( $parms ); |
| 113 | + return Xml::element( 'a', array( 'href' => $target ) + $attribs, $name ); |
| 114 | + } |
| 115 | + |
| 116 | + protected function getSelfURL( $overrides ) { |
| 117 | + $changed = $this->opts->getUnconsumedValues(); |
| 118 | + $target = $this->title->getLocalURL( wfArrayToCGI( $overrides, $changed ) ); |
| 119 | + return $target; |
| 120 | + } |
| 121 | + |
| 122 | + protected function selfLink2( $title, $overrides ) { |
| 123 | + $changed = $this->opts->getUnconsumedValues(); |
| 124 | + $target = $this->title->getLocalURL( wfArrayToCGI( $overrides, $changed ) ); |
| 125 | + return Xml::tags( 'a', array( 'href' => $target ), $title ); |
| 126 | + } |
| 127 | + |
| 128 | + protected function menuItem( $mode, $text ) { |
| 129 | + $params = array( 'mode' => $mode ); |
| 130 | + return Xml::tags( 'li', null, $this->selfLink2( $text, $params ) ); |
| 131 | + } |
| 132 | + |
| 133 | + const APCURL = 'http://pecl.php.net/package/APC'; |
| 134 | + protected function getLogo() { |
| 135 | + global $wgOut; |
| 136 | + |
| 137 | + $logo = |
| 138 | + Xml::wrapClass( Xml::element( 'a', array( 'href' => self::APCURL) , 'APC' ), 'mw-apc-logo' ) . |
| 139 | + Xml::wrapClass( 'Opcode Cache', 'mw-apc-nameinfo' ); |
| 140 | + |
| 141 | + $wgOut->addHTML( |
| 142 | + Xml::openElement( 'div', array( 'class' => 'head' ) ) . |
| 143 | + Xml::tags( 'h1', array( 'class' => 'apc-header-1' ), |
| 144 | + Xml::wrapClass( $logo, 'mw-apc-logo-outer', 'span' ) |
| 145 | + ) . |
| 146 | + |
| 147 | + Xml::wrapClass( '', 'mw-apc-separator', 'hr' ) . |
| 148 | + Xml::closeElement( 'div' ) |
| 149 | + ); |
| 150 | + |
| 151 | + } |
| 152 | + |
| 153 | + protected function mainMenu() { |
| 154 | + |
| 155 | + |
| 156 | + $clearParams = array( |
| 157 | + 'clearcache' => 1, |
| 158 | + ); |
| 159 | + $clearText = $this->opts->getValue( 'mode' ) === self::MODE_USER_CACHE ? |
| 160 | + wfMsgExt( 'viewapc-clear-user-cache', 'escape' ) : |
| 161 | + wfMsgExt( 'viewapc-clear-code-cache', 'escape' ); |
| 162 | + |
| 163 | + global $wgOut; |
| 164 | + $wgOut->addHTML( |
| 165 | + Xml::openElement( 'ol', array( 'class' => 'mw-apc-menu' ) ) . |
| 166 | + $this->menuItem( self::MODE_STATS, wfMsgExt( 'viewapc-mode-stats', 'escape' ) ) . |
| 167 | + $this->menuItem( self::MODE_SYSTEM_CACHE, wfMsgExt( 'viewapc-mode-system-cache', 'escape' ) ) . |
| 168 | + //$this->menuItem( self::MODE_SYSTEM_CACHE_DIR, wfMsgExt( 'viewapc-mode-system-cache-dir', 'escape' )) . |
| 169 | + $this->menuItem( self::MODE_USER_CACHE, wfMsgExt( 'viewapc-mode-user-cache', 'escape' )). |
| 170 | + $this->menuItem( self::MODE_VERSION_CHECK, wfMsgExt( 'viewapc-mode-version-check', 'escape' )) . |
| 171 | + Xml::tags( 'li', null, |
| 172 | + $this->selfLink2( $clearText, $clearParams ) ) . |
| 173 | + Xml::closeElement( 'ol' ) |
| 174 | + ); |
| 175 | + } |
| 176 | + |
| 177 | + |
| 178 | + |
| 179 | + protected function doObHostStats() { |
| 180 | + global $wgOut, $wgLang; |
| 181 | + |
| 182 | + $mem = apc_sma_info(); |
| 183 | + |
| 184 | + $clear = Xml::element( 'br', array( 'style' => 'clear: both;' ) ); |
| 185 | + |
| 186 | + $usermode = $this->opts->getValue( 'mode' ) === self::MODE_USER_CACHE; |
| 187 | + $cache = apc_cache_info( $usermode ? 'user' : 'opcode' ); |
| 188 | + |
| 189 | + |
| 190 | + $wgOut->addHTML( |
| 191 | + APCHostMode::doGeneralInfoTable( $cache, $mem ) . |
| 192 | + APCHostMode::doMemoryInfoTable( $cache, $mem, $this->title ) . $clear . |
| 193 | + APCHostMode::doCacheTable( $cache ) . |
| 194 | + APCHostMode::doCacheTable( apc_cache_info('user', 1), true ) . $clear . |
| 195 | + APCHostMode::doRuntimeInfoTable( $mem ) . |
| 196 | + APCHostMode::doFragmentationTable( $mem, $this->title ) . $clear |
| 197 | + ); |
| 198 | + |
| 199 | + } |
| 200 | + |
| 201 | + |
| 202 | + protected function doPage() { |
| 203 | + global $wgOut; |
| 204 | + $wgOut->addHTML( |
| 205 | + Xml::openElement( 'div', array( 'class' => 'mw-apc-content' ) ) |
| 206 | + ); |
| 207 | + |
| 208 | + switch ( $this->opts->getValue('mode') ) { |
| 209 | + case self::MODE_STATS: |
| 210 | + $this->doObHostStats(); |
| 211 | + break; |
| 212 | + case self::MODE_SYSTEM_CACHE: |
| 213 | + case self::MODE_USER_CACHE: |
| 214 | + $mode = new APCCacheMode( $this->opts, $this->title ); |
| 215 | + $mode->cacheView(); |
| 216 | + break; |
| 217 | + case self::MODE_VERSION_CHECK: |
| 218 | + $this->versionCheck(); |
| 219 | + break; |
| 220 | + } |
| 221 | + |
| 222 | + $wgOut->addHTML( |
| 223 | + Xml::closeElement( 'div' ) |
| 224 | + ); |
| 225 | + } |
| 226 | + |
| 227 | + protected function versionCheck() { |
| 228 | + global $wgOut; |
| 229 | + $wgOut->addHTML( |
| 230 | + Xml::element( 'h2', null, wfMsg( 'viewapc-version-info' ) ) |
| 231 | + ); |
| 232 | + |
| 233 | + $rss = @file_get_contents('http://pecl.php.net/feeds/pkg_apc.rss'); |
| 234 | + if (!$rss) { |
| 235 | + $wgOut->addWikiMsg( 'viewapc-version-failed' ); |
| 236 | + } else { |
| 237 | + $apcversion = phpversion('apc'); |
| 238 | + |
| 239 | + preg_match('!<title>APC ([0-9.]+)</title>!', $rss, $match); |
| 240 | + if (version_compare($apcversion, $match[1], '>=')) { |
| 241 | + $wgOut->addWikiMsg( 'viewapc-version-ok', $apcversion ); |
| 242 | + $i = 3; |
| 243 | + } else { |
| 244 | + $wgOut->addWikiMsg( 'viewapc-version-old', $apcversion, $match[1] ); |
| 245 | + $i = -1; |
| 246 | + } |
| 247 | + |
| 248 | + $wgOut->addHTML( |
| 249 | + Xml::element( 'h3', null, wfMsg( 'viewapc-version-changelog' ) ) |
| 250 | + ); |
| 251 | + |
| 252 | + |
| 253 | + preg_match_all('!<(title|description)>([^<]+)</\\1>!', $rss, $match); |
| 254 | + next($match[2]); next($match[2]); |
| 255 | + |
| 256 | + while (list(,$v) = each($match[2])) { |
| 257 | + list(,$ver) = explode(' ', $v, 2); |
| 258 | + if ($i < 0 && version_compare($apcversion, $ver, '>=')) { |
| 259 | + break; |
| 260 | + } else if (!$i--) { |
| 261 | + break; |
| 262 | + } |
| 263 | + $data = current($match[2]); |
| 264 | + $wgOut->addWikiText( "''[http://pecl.php.net/package/APC/$ver $v]''<br /><pre>$data</pre>" ); |
| 265 | + next($match[2]); |
| 266 | + } |
| 267 | + } |
| 268 | + } |
| 269 | + |
| 270 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/APC/SpecialAPC.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 271 | + native |
Index: trunk/extensions/APC/apc.css |
— | — | @@ -0,0 +1,90 @@ |
| 2 | +.mw-apc-content { |
| 3 | + clear: both; |
| 4 | + font-size: x-small; |
| 5 | +} |
| 6 | + |
| 7 | +.apc-header-1 { background:rgb(153,153,204); margin:0; padding:0.5em 1em 0.5em 1em; } |
| 8 | +.apc-header-1 a:hover { text-decoration:none; color:rgb(90,90,90); } |
| 9 | + |
| 10 | +.mw-apc-logo { |
| 11 | + background:rgb(119,123,180); |
| 12 | + border-right: solid black 1px; |
| 13 | + border-bottom: solid black 1px; |
| 14 | + font-style:italic; |
| 15 | + padding-left:1.2em; |
| 16 | + padding-right:1.2em; |
| 17 | + text-align:right; |
| 18 | +} |
| 19 | + |
| 20 | +.mw-apc-logo a { |
| 21 | + color:black; |
| 22 | +} |
| 23 | + |
| 24 | +.mw-apc-nameinfo { |
| 25 | + color:white; |
| 26 | + display:inline; |
| 27 | + font-size:0.4em; |
| 28 | + margin-left: 3em; |
| 29 | +} |
| 30 | + |
| 31 | +.mw-apc-separator { |
| 32 | + background:white; |
| 33 | + border-bottom:solid rgb(102,102,153) 1px; |
| 34 | + border-style:none; |
| 35 | + border-top:solid rgb(102,102,153) 10px; |
| 36 | + height:12px; |
| 37 | + margin:0; |
| 38 | + margin-top:1px; |
| 39 | + padding:0; |
| 40 | +} |
| 41 | + |
| 42 | +.mw-apc-stats { |
| 43 | + background:rgb(238,238,238); |
| 44 | + border:solid rgb(238,238,238) 1px; |
| 45 | + margin-bottom:1em; |
| 46 | + } |
| 47 | +.mw-apc-content h2 { |
| 48 | + background:rgb(204,204,204); |
| 49 | + color:black; |
| 50 | + font-size:1em; |
| 51 | + margin:0; |
| 52 | + padding:0.1em 1em 0.1em 1em; |
| 53 | + } |
| 54 | +.mw-apc-content table { |
| 55 | + border:solid rgb(204,204,204) 1px; |
| 56 | + border-spacing:0; |
| 57 | + width:100%; |
| 58 | + border:solid rgb(204,204,204) 1px; |
| 59 | + color:black; |
| 60 | + } |
| 61 | +.mw-apc-content table th { |
| 62 | + background:rgb(204,204,204); |
| 63 | + color:white; |
| 64 | + margin:0; |
| 65 | + padding:0.1em 1em 0.1em 1em; |
| 66 | + } |
| 67 | +.mw-apc-content th a.sortable { color:black; } |
| 68 | +.mw-apc-content td { padding:0.3em 1em 0.3em 1em; } |
| 69 | +.mw-apc-tr-0 { background:rgb(238,238,238); } |
| 70 | +.mw-apc-tr-1 { background:rgb(221,221,221); } |
| 71 | +.mw-apc-td-0 { border-right:solid rgb(102,102,153) 1px; white-space:nowrap; } |
| 72 | +.mw-apc-td-n { border-right:solid rgb(102,102,153) 1px; } |
| 73 | + |
| 74 | +.mw-apc-content td { padding:0.3em 1em 0.3em 1em; } td h3 { |
| 75 | + color:black; |
| 76 | + font-size:1.1em; |
| 77 | + margin-left:-0.3em; |
| 78 | + } |
| 79 | + |
| 80 | + |
| 81 | +.mw-apc-stats { margin:1em; width:45%; float: left; display: table;} |
| 82 | + |
| 83 | +span.box { |
| 84 | + border: black solid 1px; |
| 85 | + border-right:solid black 2px; |
| 86 | + border-bottom:solid black 2px; |
| 87 | + padding:0 0.5em 0 0.5em; |
| 88 | + margin-right:1em; |
| 89 | +} |
| 90 | +span.green { background:#60F060; padding:0 0.5em 0 0.5em} |
| 91 | +span.red { background:#D06030; padding:0 0.5em 0 0.5em } |
\ No newline at end of file |
Property changes on: trunk/extensions/APC/apc.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 92 | + native |
Index: trunk/extensions/APC/APCHostMode.php |
— | — | @@ -0,0 +1,202 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class APCHostMode { |
| 5 | + |
| 6 | + public static function doGeneralInfoTable( $c, $mem ) { |
| 7 | + global $wgLang; |
| 8 | + $r = 1; |
| 9 | + return |
| 10 | + APCUtils::tableHeader( wfMsg( 'viewapc-info-general' ) ) . |
| 11 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-apc-version' ), phpversion('apc') ) . |
| 12 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-php-version' ), phpversion() ) . |
| 13 | + |
| 14 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-shared-memory' ), |
| 15 | + wfMsgExt( 'viewapc-shared-memory-details', 'parsemag', |
| 16 | + $wgLang->formatNum( $mem['num_seg'] ), |
| 17 | + $wgLang->formatSize( $mem['seg_size'] ), |
| 18 | + $c['memory_type'], $c['locking_type'] ) ) . |
| 19 | + |
| 20 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-start-time' ), |
| 21 | + $wgLang->timeanddate( $c['start_time'] ) ) . |
| 22 | + |
| 23 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-uptime' ), |
| 24 | + $wgLang->formatTimePeriod( time() - $c['start_time'] ) ) . |
| 25 | + |
| 26 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-upload-support' ), $c['file_upload_progress'] ) . |
| 27 | + APCUtils::tableFooter(); |
| 28 | + } |
| 29 | + |
| 30 | + public static function doCacheTable( $c, $user = false ) { |
| 31 | + global $wgLang; |
| 32 | + |
| 33 | + // Calculate rates |
| 34 | + $numHits = $wgLang->formatNum( $c['num_hits'] ); |
| 35 | + $numMiss = $wgLang->formatNum( $c['num_misses'] ); |
| 36 | + $numReqs = $c['num_hits']+$c['num_misses']; |
| 37 | + $cPeriod = time()-$c['start_time']; |
| 38 | + $rateReqs = APCUtils::formatReqPerS( $numReqs / $cPeriod ); |
| 39 | + $rateHits = APCUtils::formatReqPerS( $c['num_hits'] / $cPeriod ); |
| 40 | + $rateMiss = APCUtils::formatReqPerS( $c['num_misses'] / $cPeriod ); |
| 41 | + $rateInsert= APCUtils::formatReqPerS( $c['num_inserts'] / $cPeriod ); |
| 42 | + |
| 43 | + $cachedFiles = wfMsgExt( 'viewapc-cached-files-d', 'parsemag', |
| 44 | + $wgLang->formatNum( $c['num_entries'] ), |
| 45 | + $wgLang->formatSize( $c['mem_size'] ) ); |
| 46 | + $cacheFullCount = $wgLang->formatNum( $c['expunges'] ); |
| 47 | + |
| 48 | + $contentType = !$user ? wfMsg( 'viewapc-filecache-info' ) : wfMsg( 'viewapc-usercache-info' ); |
| 49 | + |
| 50 | + return |
| 51 | + APCUtils::tableHeader( $contentType ) . |
| 52 | + APCUtils::tableRow( $r=0, wfMsgHtml( 'viewapc-cached-files' ), $cachedFiles ) . |
| 53 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-hits' ), $numHits ) . |
| 54 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-misses' ), $numMiss ) . |
| 55 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-requests' ), $rateReqs ) . |
| 56 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-hitrate' ), $rateHits ) . |
| 57 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-missrate' ), $rateMiss ) . |
| 58 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-insertrate' ), $rateInsert ) . |
| 59 | + APCUtils::tableRow( $r=1-$r, wfMsgHtml( 'viewapc-cachefull' ), $cacheFullCount ) . |
| 60 | + APCUtils::tableFooter(); |
| 61 | + } |
| 62 | + |
| 63 | + public static function doRuntimeInfoTable( $mem ) { |
| 64 | + $s = APCUtils::tableHeader( wfMsg( 'viewapc-info-runtime' ) ); |
| 65 | + |
| 66 | + $r = 1; |
| 67 | + foreach (ini_get_all('apc') as $k => $v) { |
| 68 | + $s .= APCUtils::tableRow( $r=1-$r, |
| 69 | + htmlspecialchars( $k ), |
| 70 | + str_replace(',',',<br />', htmlspecialchars($v['local_value']) ) ); |
| 71 | + } |
| 72 | + |
| 73 | + $s .= APCUtils::tableFooter(); |
| 74 | + return $s; |
| 75 | + } |
| 76 | + |
| 77 | + public static function doMemoryInfoTable( $c, $mem, $title ) { |
| 78 | + global $wgLang; |
| 79 | + |
| 80 | + $s = APCUtils::tableHeader( wfMsg( 'viewapc-info-memory' ), 'mw-apc-img-table' ); |
| 81 | + |
| 82 | + if ( $mem['num_seg'] > 1 || $mem['num_seg'] == 1 && count($mem['block_lists'][0]) > 1 ) { |
| 83 | + $memHeader = wfMsgExt( 'viewapc-memory-usage-detailed', 'parseinline' ); |
| 84 | + } else { |
| 85 | + $memHeader = wfMsgExt( 'viewapc-memory-usage', 'parseinline' ); |
| 86 | + } |
| 87 | + $hitHeader = wfMsgExt( 'viewapc-cache-efficiency', 'parseinline' ); |
| 88 | + |
| 89 | + $s .= APCUtils::tableRow( null, $memHeader, $hitHeader ); |
| 90 | + |
| 91 | + |
| 92 | + if ( APCImages::graphics_avail() ) { |
| 93 | + $attribs = array( |
| 94 | + 'alt' => '', |
| 95 | + 'width' => APCImages::GRAPH_SIZE+10, |
| 96 | + 'height' => APCImages::GRAPH_SIZE+10, |
| 97 | + ); |
| 98 | + |
| 99 | + $param1 = wfArrayToCGI( array( 'image' => APCImages::IMG_MEM_USAGE ) ); |
| 100 | + $param2 = wfArrayToCGI( array( 'image' => APCImages::IMG_HITS ) ); |
| 101 | + |
| 102 | + $attribs1 = array( 'src' => $title->getLocalURL( $param1 ) ) + $attribs; |
| 103 | + $attribs2 = array( 'src' => $title->getLocalURL( $param2 ) ) + $attribs; |
| 104 | + |
| 105 | + $s .= APCUtils::tableRow( null, Xml::element( 'img', $attribs1 ), Xml::element( 'img', $attribs2 ) ); |
| 106 | + } |
| 107 | + |
| 108 | + $size = $mem['num_seg'] * $mem['seg_size']; |
| 109 | + $free = $mem['avail_mem']; |
| 110 | + $used = $size - $free; |
| 111 | + |
| 112 | + $freeMem = wfMsgExt( 'viewapc-memory-free', 'parseinline', |
| 113 | + $wgLang->formatSize( $free ), |
| 114 | + $wgLang->formatNum( sprintf('%.1f%%', $free*100/$size) ) ); |
| 115 | + |
| 116 | + $usedMem = wfMsgExt( 'viewapc-memory-used', 'parseinline', |
| 117 | + $wgLang->formatSize( $used ), |
| 118 | + $wgLang->formatNum( sprintf('%.1f%%', $used*100/$size) ) ); |
| 119 | + |
| 120 | + $hits = $c['num_hits']; |
| 121 | + $miss = $c['num_misses']; |
| 122 | + $reqs = $hits + $miss; |
| 123 | + |
| 124 | + $greenbox = Xml::element( 'span', array( 'class' => 'green box' ), ' ' ); |
| 125 | + $redbox = Xml::element( 'span', array( 'class' => 'red box' ), ' ' ); |
| 126 | + |
| 127 | + $memHits = wfMsgExt( 'viewapc-memory-hits', 'parseinline', |
| 128 | + $wgLang->formatNum( $hits ), |
| 129 | + $wgLang->formatNum( @sprintf('%.1f%%', $hits*100/$reqs) ) ); |
| 130 | + |
| 131 | + $memMiss = wfMsgExt( 'viewapc-memory-miss', 'parseinline', |
| 132 | + $wgLang->formatNum( $miss ), |
| 133 | + $wgLang->formatNum( @sprintf('%.1f%%', $miss*100/$reqs) ) ); |
| 134 | + |
| 135 | + $s .= APCUtils::tableRow( null, $greenbox . $freeMem, $greenbox . $memHits ); |
| 136 | + $s .= APCUtils::tableRow( null, $redbox . $usedMem, $redbox . $memMiss ); |
| 137 | + $s .= APCUtils::tableFooter(); |
| 138 | + |
| 139 | + return $s; |
| 140 | + } |
| 141 | + |
| 142 | + public static function doFragmentationTable( $mem, $title ) { |
| 143 | + global $wgLang; |
| 144 | + $s = APCUtils::tableHeader( wfMsg( 'viewapc-memoryfragmentation' ), 'mw-apc-img-table' ); |
| 145 | + $s .= Xml::openElement( 'tr' ) . Xml::openElement( 'td' ); |
| 146 | + |
| 147 | + // Fragementation: (freeseg - 1) / total_seg |
| 148 | + $nseg = $freeseg = $fragsize = $freetotal = 0; |
| 149 | + for( $i = 0; $i < $mem['num_seg']; $i++ ) { |
| 150 | + $ptr = 0; |
| 151 | + foreach( $mem['block_lists'][$i] as $block ) { |
| 152 | + if ( $block['offset'] != $ptr ) { |
| 153 | + ++$nseg; |
| 154 | + } |
| 155 | + $ptr = $block['offset'] + $block['size']; |
| 156 | + /* Only consider blocks <5M for the fragmentation % */ |
| 157 | + if( $block['size'] < (5*1024*1024) ) $fragsize += $block['size']; |
| 158 | + $freetotal += $block['size']; |
| 159 | + } |
| 160 | + $freeseg += count($mem['block_lists'][$i]); |
| 161 | + } |
| 162 | + |
| 163 | + |
| 164 | + if (APCImages::graphics_avail()) { |
| 165 | + $attribs = array( |
| 166 | + 'alt' => '', |
| 167 | + 'width' => 2*APCImages::GRAPH_SIZE+150, |
| 168 | + 'height' => APCImages::GRAPH_SIZE+10, |
| 169 | + 'src' => $title->getLocalURL( 'image=' . APCImages::IMG_FRAGMENTATION) |
| 170 | + ); |
| 171 | + $s .= Xml::element( 'img', $attribs ); |
| 172 | + } |
| 173 | + |
| 174 | + if ($freeseg > 1) { |
| 175 | + $fragPercent = sprintf( '%.2f%%', ($fragsize/$freetotal)*100 ); |
| 176 | + $s .= wfMsgExt( 'viewapc-fragmentation-info', 'parse', |
| 177 | + $wgLang->formatNum( $fragPercent, true), |
| 178 | + $wgLang->formatSize( $fragsize ), |
| 179 | + $wgLang->formatSize( $freetotal ), |
| 180 | + $wgLang->formatNum( $freeseg ) |
| 181 | + ); |
| 182 | + } else { |
| 183 | + $s .= wfMsgExt( 'viewapc-fragmentation-none', 'parse' ); |
| 184 | + } |
| 185 | + |
| 186 | + $s .= Xml::closeElement( 'td' ) . Xml::closeElement( 'tr' ); |
| 187 | + |
| 188 | + if(isset($mem['adist'])) { |
| 189 | + foreach($mem['adist'] as $i=>$v) { |
| 190 | + $cur = pow(2,$i); $nxt = pow(2,$i+1)-1; |
| 191 | + if($i==0) $range = "1"; |
| 192 | + else $range = "$cur - $nxt"; |
| 193 | + $s .= Xml::tags( 'tr', null, |
| 194 | + Xml::tags( 'th', array( 'align' => 'right' ), $range ) . |
| 195 | + Xml::tags( 'td', array( 'align' => 'right' ), $v ) |
| 196 | + ); |
| 197 | + } |
| 198 | + } |
| 199 | + |
| 200 | + $s .= APCUtils::tableFooter(); |
| 201 | + return $s; |
| 202 | + } |
| 203 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/APC/APCHostMode.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 204 | + native |