├── OSSMETADATA ├── conf └── rpm.spec ├── root └── apps │ └── apache │ ├── conf.d │ └── admin_gc_viz.conf │ └── htdocs │ └── AdminGCViz │ ├── remote-data-collection │ ├── prepend_epoch.py │ ├── facet_events_by_type.sh │ ├── gc_events_by_type.sh │ ├── facet_events_by_country.sh │ ├── gcdotlog_extract_sizes.pl │ ├── gcdotlog_one_event_per_line.pl │ ├── parse-proc-pid-maps.py │ ├── vms_facet_info_transform.py │ ├── gcdotlog_convert_relative_into_absolute_time.py │ ├── gcdotlog_extract_time.pl │ ├── process_vms_object_cache_stats.py │ └── collect_remote_data.sh │ ├── gc_event_types │ ├── index │ ├── vmsgcvizutils.py │ ├── BUGS │ ├── README │ ├── visualize-facets.py │ ├── generate │ └── visualize-gc.py ├── LICENSE ├── README └── INSTALL /OSSMETADATA: -------------------------------------------------------------------------------- 1 | osslifecycle=archived 2 | -------------------------------------------------------------------------------- /conf/rpm.spec: -------------------------------------------------------------------------------- 1 | Name: @name@ 2 | Summary: Netflix GC Visualization 3 | Version: @version@ 4 | Release: @release@ 5 | License: NFLX 6 | Packager: Engineering Tools 7 | Vendor: Netflix, Inc. 8 | Group: Netflix Base 9 | AutoReqProv: no 10 | Requires: nflx-python-matplotlib, nflx-python-numpy, nflx-python-scipy 11 | 12 | %description 13 | GC Visualization 14 | ---------- 15 | @build.metadata@ 16 | 17 | %install 18 | cat $0 > %{_topdir}/install.txt 19 | mkdir -p $RPM_BUILD_ROOT 20 | mv ${RPM_BUILD_DIR}/* $RPM_BUILD_ROOT 21 | 22 | %clean 23 | rm -rf $RPM_BUILD_ROOT/* 24 | 25 | %files 26 | %defattr(-,root,root) 27 | / 28 | 29 | %post 30 | -------------------------------------------------------------------------------- /root/apps/apache/conf.d/admin_gc_viz.conf: -------------------------------------------------------------------------------- 1 | 2 | # configuration for GC visualization admin app 3 | # mounted under /AdminGCViz and /AdminGCVizImages 4 | 5 | ScriptAlias /AdminGCViz/ "/apps/apache/htdocs/AdminGCViz/" 6 | Alias /AdminGCVizImages/ "/mnt/logs/gc-reports/" 7 | 8 | 9 | Order deny,allow 10 | Deny from all 11 | Allow from 127.0.0.1/32 12 | 13 | 14 | # send requests to /AdminGCViz [with and without trailing /] to /index 15 | RewriteRule ^/AdminGCViz/?$ /AdminGCViz/index [R] 16 | # Force apache to handle the rest [this catches AdminGCVizImages too] 17 | RewriteRule ^/AdminGCViz - [L] 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2013 Netflix, Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/prepend_epoch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/prepend_epoch.py#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | import fileinput 9 | import sys 10 | 11 | # Ugh. 12 | sys.path.insert(0, "/apps/apache/htdocs/AdminGCViz") 13 | import vmsgcvizutils 14 | 15 | def mayne(): 16 | print "secs_since_epoch" 17 | for line in fileinput.input('-'): 18 | line = line.rstrip('\r\n') 19 | print "%s" % (vmsgcvizutils.timestamp_to_epoch(line),) 20 | 21 | if __name__ == "__main__": 22 | mayne() 23 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/gc_event_types: -------------------------------------------------------------------------------- 1 | ParNew (stop-the-world) 2 | CMS-initial-mark (stop-the-world) 3 | CMS-concurrent-mark (concurrent includes yields to other theads) 4 | CMS-concurrent-abortable-preclean (concurrent) 5 | CMS-concurrent-preclean (concurrent) 6 | CMS-remark (stop the world) 7 | CMS-concurrent-sweep (concurrent) 8 | CMS-concurrent-reset (concurrent?) 9 | concurrent mode failure (stop the world) 10 | promotion failed (stop the world) 11 | Full GC (stop the world) 12 | 13 | markers 14 | CMS-concurrent-mark-start 15 | CMS-concurrent-preclean-start 16 | CMS-concurrent-sweep-start 17 | CMS-concurrent-reset-start 18 | CMS-concurrent-abortable-preclean-start 19 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/facet_events_by_type.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/facet_events_by_type.sh#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | if [ -z "$1" ]; then 9 | echo Usage: $0 output-dir 10 | exit 1 11 | fi 12 | 13 | OUTPUTDIR=$1 14 | OUTDIR=${OUTPUTDIR}/facet-events-by-cache 15 | INFILE=${OUTPUTDIR}/vms-cache-refresh-facet-info.csv 16 | mkdir -p ${OUTDIR} 17 | EVENT_TYPES=`awk -F, '{print $4}' ${INFILE} | sort -u | grep -v cache` 18 | echo event_Types is ${EVENT_TYPES} 19 | for e in ${EVENT_TYPES}; 20 | do 21 | echo egrep -e ${e} -e seconds_since_epoch ${INFILE} \> ${OUTDIR}/${e} 22 | egrep -e ${e} -e seconds_since_epoch ${INFILE} > ${OUTDIR}/${e} 23 | done 24 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/gc_events_by_type.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/gc_events_by_type.sh#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | if [ -z "$1" ]; then 9 | echo Usage: $0 output-dir 10 | exit 1 11 | fi 12 | 13 | OUTPUTDIR=$1 14 | OUTDIR=${OUTPUTDIR}/gc-events-duration-by-event 15 | INFILE=${OUTPUTDIR}/gc-events-duration-in-seconds-only 16 | mkdir -p ${OUTDIR} 17 | EVENT_TYPES=`awk -F, '{print $4}' ${INFILE} | sort -u | grep -v gc_event_type` 18 | echo event_Types is ${EVENT_TYPES} 19 | for e in ${EVENT_TYPES}; 20 | do 21 | echo egrep -e ${e} -e secs_since_epoch ${INFILE} \> ${OUTDIR}/${e} 22 | egrep -e ${e} -e secs_since_epoch ${INFILE} > ${OUTDIR}/${e} 23 | done 24 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/facet_events_by_country.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/facet_events_by_country.sh#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | if [ -z "$1" ]; then 9 | echo Usage: $0 output-dir 10 | exit 1 11 | fi 12 | 13 | OUTPUTDIR=$1 14 | OUTDIR=${OUTPUTDIR}/facet-events-by-country 15 | INFILE=${OUTPUTDIR}/vms-cache-refresh-facet-info.csv 16 | mkdir -p ${OUTDIR} 17 | EVENT_TYPES=`awk -F, '{print $3}' ${INFILE} | sort -u | grep -v country` 18 | echo event_Types is ${EVENT_TYPES} 19 | for e in ${EVENT_TYPES}; 20 | do 21 | echo egrep -e ,${e}, -e seconds_since_epoch ${INFILE} \> ${OUTDIR}/${e} 22 | egrep -e ,${e}, -e seconds_since_epoch ${INFILE} > ${OUTDIR}/${e} 23 | done 24 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/gcdotlog_extract_sizes.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/gcdotlog_extract_sizes.pl#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | use strict; 9 | 10 | my $num_args = $#ARGV + 1; 11 | 12 | if($num_args != 1) { 13 | die "Usage: $0 output-dir"; 14 | } 15 | 16 | my $outputdir = $ARGV[0]; 17 | my $fname = "${outputdir}/gcdotlog_extract_sizes_rejected_lines"; 18 | open(REJECTS, ">$fname") or die "cannot open $fname for writing"; 19 | 20 | print "datetimestamp,secs_since_jvm_boot,young_begin_k,young_end_k,young_total_k,whole_heap_begin_k,whole_heap_end_k,whole_heap_total_k\n"; 21 | while() { 22 | my $line = $_; 23 | chomp($line); 24 | 25 | if(0) { 26 | # make all the lines elsif to make moving blocks easier 27 | } 28 | elsif($line =~ m/->.*->.*->/) { 29 | # reject lines with three arrows 30 | print REJECTS "$line\n"; 31 | } 32 | elsif($line =~ m/^([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}[.][0-9]{3}[+]0000): ([0-9]+[.][0-9]{3}): .* ([0-9]+)K->([0-9]+)K\(([0-9]+)K\).* ([0-9]+)K->([0-9]+)K\(([0-9]+)K\)/) { 33 | print "$1,$2,$3,$4,$5,$6,$7,$8\n"; 34 | } 35 | else { 36 | print REJECTS "$line\n"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/index: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/index#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Author: mooreb $ 6 | # $Change: 1838706 $ 7 | 8 | cd `dirname $0` 9 | 10 | prog=`basename $0` 11 | 12 | NFENV=/etc/profile.d/netflix_environment.sh 13 | if [ -f ${NFENV} ]; then 14 | . ${NFENV} 15 | NETFLIX_VMS_EVENTS=checked 16 | else 17 | NFENV="" 18 | fi 19 | 20 | cat < 24 | 25 | AdminGCViz 26 | 27 | 28 | EndOfHeader 29 | 30 | cat < 33 | jmap -histo:live 34 | parse catalina logs looking for netflix VMS events 35 | 36 | 37 | EndOfGenerate 38 | 39 | echo Look at previous reports 40 | echo "" 41 | for f in `find /mnt/logs/gc-reports -type f -name "*.png" | LANG=C sort -rn`; 42 | do 43 | u=`echo ${f} | sed 's|/mnt/logs/gc-reports/||'` 44 | echo " ${f}" 45 | done 46 | echo "" 47 | 48 | 49 | cat < 51 | 52 | EndOfFooter 53 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | # Deprecation Note 2 | 3 | Gcviz is no longer maintained and should be considered archived. 4 | 5 | Note that gcviz code is not intended to be deployed on untrusted networks, or without external authentication and authorization. Specifically, it has functionality that can allow execution of system commands by remote users. 6 | 7 | # Original README 8 | 9 | This is gcviz, a set of programs that help generate visualizations 10 | from gc.log, a log file that the HotSpot, a Java Virual Machine, 11 | writes when configured with the following flags: 12 | -verbose:gc 13 | -verbose:sizes 14 | -Xloggc:/apps/tomcat/logs/gc.log 15 | -XX:+PrintGCDetails 16 | -XX:+PrintGCDateStamps 17 | -XX:+PrintTenuringDistribution 18 | 19 | gcviz is intended to be used as a webapp when installed on the same 20 | host as tomcat, or any other Java web container. The gcviz program 21 | itself is served by apache httpd inside netflix, but could be served 22 | by any webserver that supports CGI. gcviz implicitly assumes to 23 | be running in a linux environment. 24 | 25 | By default gcviz is available at: 26 | http://127.0.0.1:8080/AdminGCViz/index 27 | 28 | Internally, gcviz is a bundle of four sorts of things: 29 | * python programs that require matplotlib, numpy, pylab, etc. 30 | * cgi scripts that invoke these python programs 31 | * some minor assistive perl scripts 32 | * very minor rpm infrastructure to package the previous things. 33 | 34 | I wrote gcviz to address challenges we face inside Netflix. If you 35 | feel that any changes you might propose could be helpful for Netflix 36 | or for the community at large, please write. 37 | 38 | Brian Moore 39 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/gcdotlog_one_event_per_line.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/gcdotlog_one_event_per_line.pl#3 $ 4 | # $DateTime: 2013/11/05 12:09:10 $ 5 | # $Change: 2024106 $ 6 | # $Author: mooreb $ 7 | 8 | use strict; 9 | 10 | sub flush_previous_record { 11 | my ($previous_record) = @_; 12 | if ("" ne "$previous_record") { 13 | print "$previous_record\n"; 14 | } 15 | } 16 | 17 | my $previous_record = ""; 18 | while() { 19 | my $line = $_; 20 | chomp($line); 21 | # -XX:+PrintGCDateStamps 22 | if($line =~ m/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}/) { 23 | # starting a new record 24 | flush_previous_record($previous_record); 25 | $previous_record = $line; 26 | } 27 | elsif($line =~ m/^[0-9]+[.][0-9]+: /) { 28 | # starting a new record 29 | flush_previous_record($previous_record); 30 | $previous_record = $line; 31 | } 32 | elsif($line =~ m/(^.*[0-9]+[.][0-9]+ secs])([0-9]+[.][0-9]+: .*$)/) { 33 | # two records are conflated 34 | $previous_record = $previous_record . $1; 35 | flush_previous_record($previous_record); 36 | $previous_record = $2; 37 | } 38 | elsif($line =~ m/(^.*)([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.*)/) { 39 | # two records (with -XX:+PrintGCDateStamps) are conflated 40 | $previous_record = $previous_record . $1; 41 | flush_previous_record($previous_record); 42 | $previous_record = $2; 43 | } 44 | else { 45 | # append to the previous record 46 | $previous_record = $previous_record . $line; 47 | } 48 | } 49 | flush_previous_record($previous_record); 50 | 51 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/parse-proc-pid-maps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/parse-proc-pid-maps.py#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | import sys 9 | 10 | def bytesToHumanReadable(n): 11 | kay = 1024 12 | meg = kay*1024 13 | gig = meg*1024 14 | if ((0 <= n) and (n < kay)): 15 | return "%d bytes" % n 16 | elif ((kay <= n) and (n < meg)): 17 | return "%.2fkb" % ((n+0.0)/kay) 18 | elif ((meg <= n) and (n < gig)): 19 | return "%.2fmb" % ((n+0.0)/meg) 20 | else: 21 | return "%.2fgb" % ((n+0.0)/gig) 22 | 23 | def readfile(filename): 24 | segments = [] 25 | numSegments=0L 26 | totalBytes=0L 27 | infile = open(filename, 'r') 28 | line = infile.readline() 29 | while line: 30 | line = line.rstrip() 31 | fields = line.split(None, 5) 32 | if 6 == len(fields): 33 | (memRange, perms, offset, dev, inode, pathname) = fields 34 | elif 5 == len(fields): 35 | (memRange, perms, offset, dev, inode) = fields 36 | pathname = '' 37 | else: 38 | raise Exception('cannot unpack %s' % (line,)) 39 | (begin,end) = memRange.split('-') 40 | t = long(end, 16) - long(begin, 16) 41 | totalBytes = totalBytes + t 42 | numSegments = numSegments + 1 43 | x = (t, memRange, pathname) 44 | segments.append(x) 45 | line = infile.readline() 46 | print filename 47 | print "\tnum segments = %s" % (numSegments,) 48 | print "\ttotal bytes = %s (%s)" % (totalBytes, bytesToHumanReadable(totalBytes)) 49 | for i in sorted(segments, key=lambda x: x[0], reverse=True): 50 | print "\t\t%12s bytes (%s) %33s %s" % (i[0], bytesToHumanReadable(i[0]), i[1], i[2]) 51 | 52 | readfile(sys.argv[1]) 53 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/vms_facet_info_transform.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/vms_facet_info_transform.py#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | import fileinput 9 | import re 10 | 11 | # Ugh. 12 | sys.path.insert(0, "/apps/apache/htdocs/AdminGCViz") 13 | import vmsgcvizutils 14 | 15 | # Input: 16 | # 2012-03-30 00:47:11,771 country(GF) cache(VideoImages) numItems(24189) totalTime(1397531) timeToCopyToDisc(5550) timeToFill(1391981) 17 | # ... 18 | # 19 | # Output 20 | # seconds_since_epoch,datetimestamp,country,cache,numitems,totalTime,timeToCopyToDisc,timeToFill 21 | # 1333068431.771,2012-03-30T00:47:11.771+0000,GF,VideoImages,24189,1397531,5550,1391981 22 | # ... 23 | 24 | facetPattern = re.compile('^([0-9]{4}-[0-9]{2}-[0-9]{2}) ([0-9]{2}:[0-9]{2}:[0-9]{2}),([0-9]{3}) country\(([A-Z]{2})\) cache\(([^)]+)\) numItems\(([0-9]+)\) totalTime\(([0-9]+)\) timeToCopyToDisc\(([0-9]+)\) timeToFill\(([0-9]+)\)$') 25 | 26 | print 'seconds_since_epoch,datetimestamp,country,cache,numitems,totalTime,timeToCopyToDisc,timeToFill' 27 | for line in fileinput.input('-'): 28 | line = line.rstrip('\r\n') 29 | found = facetPattern.search(line) 30 | if found: 31 | ymd = found.group(1) 32 | hms = found.group(2) 33 | milliseconds = found.group(3) 34 | iso8601Timestamp = '%sT%s.%s+0000' % (ymd,hms,milliseconds) 35 | secsSinceEpoch = vmsgcvizutils.timestamp_to_epoch(iso8601Timestamp) 36 | country = found.group(4) 37 | cache = found.group(5) 38 | numItems = found.group(6) 39 | totalTime = found.group(7) 40 | timeToCopyToDisc = found.group(8) 41 | timeToFill = found.group(9) 42 | print '%s,%s,%s,%s,%s,%s,%s,%s' % (secsSinceEpoch, iso8601Timestamp, country, cache, numItems, totalTime, timeToCopyToDisc, timeToFill) 43 | else: 44 | sys.stderr.write(line) 45 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/vmsgcvizutils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/vmsgcvizutils.py#3 $ 4 | # $DateTime: 2013/11/12 19:42:41 $ 5 | # $Change: 2030932 $ 6 | # $Author: mooreb $ 7 | 8 | import calendar 9 | import math 10 | import time 11 | import re 12 | 13 | def timestamp_to_epoch(timeStringISO8601): 14 | # Potential BUG: +0000 is hardcoded. I'd like to use %z but 15 | # cannot, as it's not supported by time.strptime and there's no 16 | # easy workaround: http://wiki.python.org/moin/WorkingWithTime 17 | secondFractionPattern = re.compile('([.][0-9]+)[+]0000') 18 | match = secondFractionPattern.search(timeStringISO8601) 19 | if match: 20 | fraction = match.group(1) 21 | else: 22 | fraction = "" 23 | timeStringISO8601 = timeStringISO8601.replace(fraction, '') 24 | # Potential BUG: +0000 is hardcoded. I'd like to use %z but 25 | # cannot, as it's not supported by time.strptime and there's no 26 | # easy workaround: http://wiki.python.org/moin/WorkingWithTime 27 | bootTimeTuple = time.strptime(timeStringISO8601, "%Y-%m-%dT%H:%M:%S+0000") 28 | bootTimeSecondsSinceEpoch = "%s" % calendar.timegm(bootTimeTuple) 29 | return (bootTimeSecondsSinceEpoch + fraction) 30 | 31 | def convertTimeStamp(absoluteBaselineTime, secondsAfterBaseline): 32 | offsetTime = absoluteBaselineTime + secondsAfterBaseline 33 | offsetTimeTuple = time.gmtime(offsetTime) 34 | # Potential BUG: +0000 is hardcoded. I'd like to use %z but 35 | # cannot, as it's not supported by time.strptime and there's no 36 | # easy workaround: http://wiki.python.org/moin/WorkingWithTime 37 | offsetTimeString = time.strftime("%Y-%m-%dT%H:%M:%S+0000", offsetTimeTuple) 38 | fractionSecondsString = '%.3f' % (secondsAfterBaseline - math.floor(secondsAfterBaseline)) 39 | retval = offsetTimeString.replace('+', fractionSecondsString[1:] + '+') 40 | return retval 41 | 42 | 43 | def envFileAsDictionary(fname): 44 | retval = {} 45 | fp = open(fname, 'r') 46 | for line in fp: 47 | line = line.rstrip('\r\n') 48 | try: 49 | (k, v) = line.split('=', 1) 50 | except ValueError: 51 | continue 52 | retval[k] = v 53 | return retval 54 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/BUGS: -------------------------------------------------------------------------------- 1 | This is more of a todo list than things that are deeply wrong, but I want to make the fringes that I know about public. 2 | 3 | * all of the BUGs and Potential BUGs in all of the sources 4 | * visualize-cluster does not work 5 | * compute throughput, allocation rate from gc data (do this with PrintGCStats?) 6 | * sar data (cpu, etc) needs to be visualized 7 | 8 | 9 | 10 | * netflix internal: need to visualize facet data 11 | * netflix internal: need to ensure that clients output vms cache refresh event overall and facet-level timing 12 | * gps 13 | * api 14 | * merchweb 15 | * ecweb (curently no facet-level timing for demand-fill) 16 | * accountweb (curently no facet-level timing for demand-fill) 17 | * ... 18 | * netflix-internal: delta fail needs to be added to catalina parsing (right now all lines are plotted as begin/end overall) 19 | * netflix-internal, maybe outside too: truncated gc logs (when ec2rotate logs purges stuff older than 7 days creates "unknown" gc events. 20 | * netflix-internal: have if -z checks for status-properties-1, -2. delete empty files. don't do both if we get the output for one. Consider getting URL from discovery/entrypoints. 21 | * netflix-internal: the squirreled away vms-gc-reports location is // and doesn't have instance id in the path... This could be a problem for visualize-cluster. 22 | * netflix-internal: Consider grabbing some number of recent ttime and threaddump files from /apps/tomcat/logs/cores 23 | drwxrwsr-x 2 root nac 94208 Apr 17 23:44 . 24 | -rw-r--r-- 1 merchwebprod nac 168050 Apr 17 23:44 ttime.20120417.234401.1586.txt 25 | lrwxrwxrwx 1 merchwebprod nac 59 Apr 17 23:44 latest -> /apps/tomcat/logs/cores/threaddump.20120417.234401.1586.txt 26 | -rw-r--r-- 1 merchwebprod nac 1117242 Apr 17 23:44 threaddump.20120417.234401.1586.txt 27 | -rw-r--r-- 1 merchwebprod nac 168251 Apr 17 23:34 ttime.20120417.233401.1586.txt 28 | -rw-r--r-- 1 merchwebprod nac 1119200 Apr 17 23:34 threaddump.20120417.233401.1586.txt 29 | -rw-r--r-- 1 merchwebprod nac 168371 Apr 17 23:24 ttime.20120417.232401.1586.txt 30 | -rw-r--r-- 1 merchwebprod nac 1120525 Apr 17 23:24 threaddump.20120417.232401.1586.txt 31 | -rw-r--r-- 1 merchwebprod nac 168490 Apr 17 23:15 ttime.20120417.231401.1586.txt 32 | * netflix-internal: visualize objectCache lines in ${OUTPUTDIR}/vms-object-cache-stats 33 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/gcdotlog_convert_relative_into_absolute_time.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/gcdotlog_convert_relative_into_absolute_time.py#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | import calendar 9 | import fileinput 10 | import math 11 | import os 12 | import sys 13 | import time 14 | import re 15 | 16 | # Ugh. 17 | sys.path.insert(0, "/apps/apache/htdocs/AdminGCViz") 18 | import vmsgcvizutils 19 | 20 | def mayne(): 21 | TMPFILE = '/tmp/gcdotlog-relative-time-tmpfile' 22 | numArgs = len(sys.argv) - 1 23 | if(2 != numArgs): 24 | print "Usage: %s {iso8601 combined date and time representations} outputdir" % (sys.argv[0],) 25 | sys.exit(1); 26 | 27 | bootTimeStringISO8601 = sys.argv[1] 28 | bootTimeSecondsSinceEpochString = vmsgcvizutils.timestamp_to_epoch(bootTimeStringISO8601) 29 | bootTimeSecondsSinceEpoch = float(bootTimeSecondsSinceEpochString) 30 | outputDir = sys.argv[2] 31 | bootTimeEpochFile = open(outputDir + '/jvm_boottime.epoch', 'w') 32 | bootTimeEpochFile.write("%s\n" % bootTimeSecondsSinceEpochString) 33 | bootTimeEpochFile.close() 34 | 35 | tmpFile = open(TMPFILE, 'w') 36 | lineStartsWithFloatingPointNumberPattern = re.compile("^([0-9]+[.][0-9]+): ") 37 | lastSecsSinceBoot = 0.0; 38 | for line in fileinput.input('-'): 39 | line = line.rstrip('\r\n') 40 | found = lineStartsWithFloatingPointNumberPattern.search(line) 41 | if found: 42 | secsSinceBootString = found.group(1) 43 | secsSinceBoot = float(secsSinceBootString) 44 | if secsSinceBoot < lastSecsSinceBoot: 45 | # now we need to truncate the output file, since we have 46 | # seen a restart; this is not the most recent JVM boot 47 | tmpFile.close() 48 | tmpFile = open(TMPFILE, 'w') 49 | lastSecsSinceBoot = secsSinceBoot 50 | timeStamp = vmsgcvizutils.convertTimeStamp(bootTimeSecondsSinceEpoch, secsSinceBoot) 51 | tmpFile.write("%s: %s\n" % (timeStamp, line)) 52 | else: 53 | tmpFile.write("%s\n" % (line,)) 54 | 55 | tmpFile.close() 56 | for line in fileinput.input(TMPFILE): 57 | line = line.rstrip('\r\n') 58 | print "%s" % (line,) 59 | 60 | os.unlink(TMPFILE) 61 | 62 | if __name__ == "__main__": 63 | mayne() 64 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | This document will attempt to describe installation of gcviz. 2 | 3 | This process is not entirely straightforward and assumes familiarity 4 | with your OS and webserver. 5 | 6 | The rest of this document assumes a *nix-style system and apache httpd. 7 | 8 | (1) Find the folder: root/apps/apache/htdocs/AdminGCViz 9 | 10 | (2) Copy this folder into your htdocs root. Assure the permissions are something like: 11 | 12 | # ls -l /apps/apache/htdocs/AdminGCViz/ 13 | total 60 14 | -rw-r--r-- 1 youruser yourgroup 2299 Mar 10 00:12 BUGS 15 | -rw-r--r-- 1 youruser yourgroup 733 Mar 10 00:12 gc_event_types 16 | -rwxr-xr-x 1 youruser yourgroup 5353 Mar 10 00:12 generate 17 | -rwxr-xr-x 1 youruser yourgroup 1253 Mar 10 00:12 index 18 | -rw-r--r-- 1 youruser yourgroup 2866 Mar 10 00:12 README 19 | drwxr-xr-x 2 youruser yourgroup 4096 Mar 14 22:22 remote-data-collection 20 | -rwxr-xr-x 1 youruser yourgroup 1670 Mar 10 00:12 visualize-cluster.py 21 | -rwxr-xr-x 1 youruser yourgroup 3478 Mar 10 00:12 visualize-facets.py 22 | -rwxr-xr-x 1 youruser yourgroup 10463 Mar 10 00:12 visualize-gc.py 23 | -rwxr-xr-x 1 youruser yourgroup 4101 Mar 10 00:12 visualize-instance.sh 24 | -rwxr-xr-x 1 youruser yourgroup 2071 Mar 10 00:12 vmsgcvizutils.py 25 | 26 | ls -l /apps/apache/htdocs/AdminGCViz/remote-data-collection/ 27 | total 52 28 | -rwxr-xr-x 1 youruser yourgroup 7776 Mar 10 00:12 collect_remote_data.sh 29 | -rwxr-xr-x 1 youruser yourgroup 707 Mar 10 00:12 facet_events_by_country.sh 30 | -rwxr-xr-x 1 youruser yourgroup 696 Mar 10 00:12 facet_events_by_type.sh 31 | -rwxr-xr-x 1 youruser yourgroup 2209 Mar 10 00:12 gcdotlog_convert_relative_into_absolute_time.py 32 | -rwxr-xr-x 1 youruser yourgroup 1177 Mar 10 00:12 gcdotlog_extract_sizes.pl 33 | -rwxr-xr-x 1 youruser yourgroup 2524 Mar 10 00:12 gcdotlog_extract_time.pl 34 | -rwxr-xr-x 1 youruser yourgroup 1554 Mar 10 00:12 gcdotlog_one_event_per_line.pl 35 | -rwxr-xr-x 1 youruser yourgroup 703 Mar 10 00:12 gc_events_by_type.sh 36 | -rwxr-xr-x 1 youruser yourgroup 1691 Mar 10 00:12 parse-proc-pid-maps.py 37 | -rwxr-xr-x 1 youruser yourgroup 556 Mar 10 00:12 prepend_epoch.py 38 | -rwxr-xr-x 1 youruser yourgroup 2778 Mar 10 00:12 process_vms_object_cache_stats.py 39 | -rwxr-xr-x 1 youruser yourgroup 1792 Mar 10 00:12 vms_facet_info_transform.py 40 | 41 | (3) Find the config file: root/apps/apache/conf.d/admin_gc_viz.conf 42 | 43 | (4) Use the config file from (3) as a guide to configure your local 44 | apache. It is intended to be Include'able (in the apache sense) but 45 | please don't blindly include it without understanding what it does and 46 | how it interacts with your other apache configuration. 47 | 48 | ADDITIONAL NOTES 49 | * you may need to ensure that the shebang line is correct for your environment. The shebang lines assume a netflix environment. 50 | * the included rpm .spec file: conf/rpm.spec may be helpful to you; YMMV 51 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/gcdotlog_extract_time.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/gcdotlog_extract_time.pl#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | use strict; 9 | 10 | sub classify_gc_event_type { 11 | my ($line) = @_; 12 | 13 | if(0) { 14 | # make all the lines "elsif" so that they are interchangable 15 | } 16 | elsif($line =~ m/Full GC/) { 17 | return "FullGC"; 18 | } 19 | elsif($line =~ m/\(concurrent mode failure\)/) { 20 | return "concurrent-mode-failure"; 21 | } 22 | elsif($line =~ m/\(promotion failed\)/) { 23 | return "promotion-failed"; 24 | } 25 | elsif($line =~ m/ParNew/) { 26 | return "ParNew"; 27 | } 28 | elsif($line =~ m/CMS-initial-mark/) { 29 | return "CMS-initial-mark"; 30 | } 31 | elsif($line =~ m/CMS-concurrent-mark/) { 32 | return "CMS-concurrent-mark"; 33 | } 34 | elsif($line =~ m/CMS-concurrent-abortable-preclean/) { 35 | return "CMS-concurrent-abortable-preclean"; 36 | } 37 | elsif($line =~ m/CMS-concurrent-preclean/) { 38 | return "CMS-concurrent-preclean"; 39 | } 40 | elsif($line =~ m/CMS-remark/) { 41 | return "CMS-remark"; 42 | } 43 | elsif($line =~ m/CMS-concurrent-sweep/) { 44 | return "CMS-concurrent-sweep"; 45 | } 46 | elsif($line =~ m/CMS-concurrent-reset/) { 47 | return "CMS-concurrent-reset"; 48 | } 49 | elsif($line =~ /PSYoungGen/) { 50 | return "ParallelScavengeYoungGen"; 51 | } 52 | elsif($line =~ /DefNew/) { 53 | return "DefNew"; 54 | } 55 | else { 56 | return "unknown"; 57 | } 58 | } 59 | 60 | sub mayne { 61 | my $num_args = $#ARGV + 1; 62 | 63 | if($num_args != 1) { 64 | die "Usage: $0 output-dir"; 65 | } 66 | 67 | my $outputdir = $ARGV[0]; 68 | my $fname = "${outputdir}/gcdotlog_extract_time_rejected_lines"; 69 | open(FP, ">$fname") or die "cannot open $fname"; 70 | 71 | print "datetimestamp,secs_since_jvm_boot,gc_event_type,gc_event_duration_in_seconds\n"; 72 | while() { 73 | my $line = $_; 74 | chomp($line); 75 | # -XX:+PrintGCDateStamps 76 | if($line =~ m/^([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}[.][0-9]{3}[+]0000): ([0-9]+[.][0-9]+): .*real=([0-9][0-9]*[.][0-9][0-9]*) secs\]\s*$/) { 77 | my $datestamp = $1; 78 | my $secs_since_jvm_boot = $2; 79 | my $gctime_in_seconds = $3; 80 | my $gc_event_type = classify_gc_event_type($line); 81 | print "${datestamp},${secs_since_jvm_boot},${gc_event_type},${gctime_in_seconds}\n"; 82 | } 83 | else { 84 | print FP "$line\n"; 85 | } 86 | } 87 | close(FP); 88 | } 89 | 90 | mayne() 91 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/README: -------------------------------------------------------------------------------- 1 | * This program is split into thee conceptual parts: 2 | * a top-level "driver" (visualize-instance.sh and visualize-cluster.py) 3 | * a remote data collection component (remote-data-collection/collect_remote_data.sh) 4 | * a visualization component (visualize-gc.py) 5 | 6 | It's difficult to get a cross-platform visualization component, so I 7 | opted for python's matplotlib, which is cross platform and has a 8 | single-click installer available for windows, macintosh and linux. 9 | 10 | * To visialize the data you'lll need python's matplotlib. One 11 | simple-to-install (and free) distribution that contains this is EPD: 12 | http://www.enthought.com/repo/free/ 13 | This will (attempt) to patch your .profile equivalent to place itself first on your PATH. 14 | 15 | * A note about how GC events are parsed. This software does not, at 16 | the time of this writing, use PrintGCFixup. Instead it uses the 17 | -XX:+PrintGCDateStamps datetime stamps (if available, secs since vm 18 | boot if not) as an anchor, and treats each of those things as an 19 | event. 20 | 21 | In this context: 22 | 2012-04-04T19:07:40.395+0000: 510958.888: [GC [1 CMS-initial-mark: 18431999K(18432000K)] 18939679K(29491200K), 0.5050890 secs] [Times: user=0.50 sys=0.00, real=0.50 secs] 23 | 2012-04-04T19:07:40.903+0000: 510959.397: [CMS-concurrent-mark-start] 24 | 2012-04-04T19:07:56.564+0000: 510975.058: [CMS-concurrent-mark: 15.410/15.661 secs] [Times: user=49.94 sys=1.89, real=15.66 secs] 25 | 2012-04-04T19:07:56.565+0000: 510975.058: [CMS-concurrent-preclean-start] 26 | 2012-04-04T19:08:23.054+0000: 511001.548: [Full GC 511001.549: [CMS2012-04-04T19:08:48.906+0000: 511027.400: [CMS-concurrent-preclean: 51.957/52.341 secs] [Times: user=76.72 sys=0.15, real=52.34 secs] 27 | (concurrent mode failure): 18431999K->16174249K(18432000K), 106.0788490 secs] 29491199K->16174249K(29491200K), [CMS Perm : 69005K->69005K(115372K)], 106.0801410 secs] [Times: user=106.01 sys=0.00, real=106.06 secs] 28 | 2012-04-04T19:10:09.150+0000: 511107.644: [GC [1 CMS-initial-mark: 16174249K(18432000K)] 16363184K(29491200K), 0.0263250 secs] [Times: user=0.02 sys=0.00, real=0.03 secs] 29 | 30 | GC events of this form: 31 | 2012-04-04T19:08:23.054+0000: 511001.548: [Full GC 511001.549: [CMS2012-04-04T19:08:48.906+0000: 511027.400: [CMS-concurrent-preclean: 51.957/52.341 secs] [Times: user=76.72 sys=0.15, real=52.34 secs] 32 | (concurrent mode failure): 18431999K->16174249K(18432000K), 106.0788490 secs] 29491199K->16174249K(29491200K), [CMS Perm : 69005K->69005K(115372K)], 106.0801410 secs] [Times: user=106.01 sys=0.00, real=106.06 secs] 33 | 34 | are represented as a Full GC requiring 106 seconds rather than the 35 | CMS-preclean part of ~52 seconds. I'm not sure if ~106 or 106-52 is 36 | the stop-the-world part, but at that long of a pause, I'm not entirely 37 | convinced that it matters. Bill Jackson votes that 106-52 is the stop 38 | the world part. He's probably right. I'm surprised that the preclean 39 | wasn't aborted. 40 | 41 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/remote-data-collection/process_vms_object_cache_stats.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/remote-data-collection/process_vms_object_cache_stats.py#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | import fileinput 9 | import os 10 | import re 11 | import sys 12 | 13 | # Ugh. 14 | sys.path.insert(0, "/apps/apache/htdocs/AdminGCViz") 15 | import vmsgcvizutils 16 | 17 | numArgs = len(sys.argv) - 1 18 | if(2 != numArgs): 19 | print "Usage: %s object-cache-stats-file outputdir" % (sys.argv[0],) 20 | sys.exit(1); 21 | 22 | objectCacheStatsFile = sys.argv[1] 23 | baseOutputDir = sys.argv[2] 24 | outputDir = baseOutputDir + os.path.sep + 'vms-object-cache-stats-by-cache' 25 | os.mkdir(outputDir) 26 | outputFiles = {} 27 | rejects = open(objectCacheStatsFile + '.rejects', 'w') 28 | 29 | timestampPattern = re.compile('^([0-9]{4}-[0-9]{2}-[0-9]{2}) ([0-9]{2}:[0-9]{2}:[0-9]{2}),([0-9]{3}) INFO (main|vms-timer-refresh) VMClientCacheManager - Processed Countries') 30 | objectCachePattern = re.compile('objectCache\(([^)]*)\) references\(([^)]*)\) size\(([^)]*)\) ratio\(([^)]*)\) prevsize\(([^)]*)\) additions\(([^)]*)\) transfers\(([^)]*)\) hits\(([^)]*)\) orphans\(([^)]*)\)') 31 | 32 | header="secsSinceEpoch,iso8601Timestamp,references,size,ratio,prevsize,additions,transfers,hits,orphans\n" 33 | 34 | iso8601Timestamp = "1970-01-01T00:00:00.000+0000" 35 | secsSinceEpoch = "0.000" 36 | for line in fileinput.input(objectCacheStatsFile): 37 | line = line.rstrip('\r\n') 38 | foundTimestamp = timestampPattern.search(line) 39 | if foundTimestamp: 40 | ymd = foundTimestamp.group(1) 41 | hms = foundTimestamp.group(2) 42 | milliseconds = foundTimestamp.group(3) 43 | iso8601Timestamp = '%sT%s.%s+0000' % (ymd,hms,milliseconds) 44 | secsSinceEpoch = vmsgcvizutils.timestamp_to_epoch(iso8601Timestamp) 45 | continue 46 | 47 | foundObjectCache = objectCachePattern.search(line) 48 | if foundObjectCache: 49 | cacheName = foundObjectCache.group(1) 50 | references = foundObjectCache.group(2) 51 | size = foundObjectCache.group(3) 52 | ratio = foundObjectCache.group(4) 53 | prevsize = foundObjectCache.group(5) 54 | additions = foundObjectCache.group(6) 55 | transfers = foundObjectCache.group(7) 56 | hits = foundObjectCache.group(8) 57 | orphans = foundObjectCache.group(9) 58 | l = "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" % (secsSinceEpoch,iso8601Timestamp,references,size,ratio,prevsize,additions,transfers,hits,orphans) 59 | f = outputFiles.get(cacheName) 60 | if f: 61 | f.write(l) 62 | else: 63 | f = open(outputDir + os.path.sep + cacheName, 'w') 64 | f.write(header) 65 | f.write(l) 66 | outputFiles[cacheName] = f 67 | continue 68 | else: 69 | rejects.write("%s\n" % (line,)) 70 | 71 | rejects.close() 72 | for fp in outputFiles.values(): 73 | fp.close() 74 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/visualize-facets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/visualize-facets.py#2 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Change: 1838706 $ 6 | # $Author: mooreb $ 7 | 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | import matplotlib.mlab as mlab 11 | import matplotlib.ticker as ticker 12 | import matplotlib.dates as mdates 13 | import matplotlib.lines as lines 14 | import pylab 15 | import sys 16 | import os 17 | import vmsgcvizutils 18 | from mpl_toolkits.mplot3d import Axes3D 19 | 20 | numArgs = len(sys.argv) - 1 21 | if(2 != numArgs): 22 | print "Usage: %s now:iso8601timestamp vms-gc-report-directory" % (sys.argv[0],) 23 | sys.exit(1); 24 | 25 | now = sys.argv[1] 26 | vmsGCReportDirectory = sys.argv[2] 27 | 28 | # seconds_since_epoch,datetimestamp,country,cache,numitems,totalTime,timeToCopyToDisc,timeToFill 29 | # 1333073736.242,2012-03-30T02:15:36.242+0000,BS,VideoEDFulfillmentData,23242,1352,757,595 30 | fnameFullPath = vmsGCReportDirectory + os.path.sep + 'vms-cache-refresh-facet-info.csv' 31 | recordset = mlab.csv2rec(fnameFullPath) 32 | 33 | countries = recordset.country 34 | countriesDict = {} 35 | countriesList = [] 36 | countryNum = 0 37 | for c in countries: 38 | cPrime = countriesDict.get(c) 39 | if cPrime: 40 | countriesList.append(cPrime) 41 | else: 42 | countryNum = countryNum + 1 43 | countriesDict[c] = countryNum 44 | countriesList.append(countryNum) 45 | 46 | caches = recordset.cache 47 | cachesDict = {} 48 | cachesList = [] 49 | cacheNum = 0 50 | for c in caches: 51 | cPrime = cachesDict.get(c) 52 | if cPrime: 53 | cachesList.append(cPrime) 54 | else: 55 | cacheNum = cacheNum + 1 56 | cachesDict[c] = cacheNum 57 | cachesList.append(cacheNum) 58 | 59 | allTimeSpentInAllFacets = 0 60 | perFacetRecordSets = [] 61 | facetEventByCacheDir = vmsGCReportDirectory + os.path.sep + 'facet-events-by-cache' 62 | dirList=os.listdir(facetEventByCacheDir) 63 | for fname in dirList: 64 | fnameFullPath = facetEventByCacheDir + os.path.sep + fname 65 | r = mlab.csv2rec(fnameFullPath) 66 | allTimeSpentInFacet = sum(r.totaltime) 67 | allTimeSpentInAllFacets = allTimeSpentInAllFacets + allTimeSpentInFacet 68 | timeToCopyFacetToDisc = sum(r.timetocopytodisc) 69 | timeToFillFacet = sum(r.timetofill) 70 | d = {'totaltime' : allTimeSpentInFacet, 71 | 'copytime' : timeToCopyFacetToDisc, 72 | 'filltime' : timeToFillFacet, 73 | 'facetName' : fname, 74 | 'recordset' : r} 75 | perFacetRecordSets.append(d) 76 | perFacetRecordSets.sort(reverse=True, key=lambda d: d['totaltime']) # sort by all time spent in facet 77 | 78 | facetReportFileName = vmsGCReportDirectory + os.path.sep + 'facet-report.txt' 79 | facetReportFP = open(facetReportFileName, 'w') 80 | for r in perFacetRecordSets: 81 | timeThisFacet = r['totaltime'] 82 | s = '%10s milliseconds spent in %25s (%5.2f%%) {copy: %5.2f%%; fill: %5.2f%%}' % ( 83 | timeThisFacet, 84 | r['facetName'], 85 | ((timeThisFacet*100.0)/allTimeSpentInAllFacets), 86 | (r['copytime']*100.0/allTimeSpentInAllFacets), 87 | (r['filltime']*100.0/allTimeSpentInAllFacets), 88 | ) 89 | facetReportFP.write("%s\n" % (s,)) 90 | print s 91 | facetReportFP.close() 92 | 93 | # BUG 94 | sys.exit(0) 95 | 96 | fig = plt.figure() 97 | ax = fig.gca(projection='3d') 98 | ax.plot(countriesList, recordset.totaltime/1000, zs=cachesList, zdir='z', marker='o') 99 | 100 | ax.set_xlabel('country') 101 | ax.set_ylabel('time to fill this country/facet (seconds)') 102 | ax.set_zlabel('facet') 103 | ax.set_title('total time to fill each facet for each country') 104 | 105 | # BUG: save all generated figures. 106 | 107 | plt.show() 108 | 109 | # sort by total time descending: 110 | # sort -t , -k 6 -rn vms-cache-refresh-facet-info.csv | more 111 | -------------------------------------------------------------------------------- /root/apps/apache/htdocs/AdminGCViz/generate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # $Id: //depot/cloud/rpms/nflx-webadmin-gcviz/root/apps/apache/htdocs/AdminGCViz/generate#3 $ 4 | # $DateTime: 2013/05/15 18:34:23 $ 5 | # $Author: mooreb $ 6 | # $Change: 1838706 $ 7 | 8 | if [[ "POST" != "${REQUEST_METHOD}" ]] ; then 9 | cat < 14 | 405 Method Not Allowed 15 | 16 | Error 17 | generate cannot be called with anything but a POST 18 | 19 |
generate cannot be called with anything but a POST