PageRenderTime 14ms CodeModel.GetById 3ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/lib/python/indra/util/simperf_proc_interface.py

https://bitbucket.org/lindenlab/viewer-beta/
Python | 191 lines | 181 code | 0 blank | 10 comment | 0 complexity | d1a1dc8660b173973faf609779de96a1 MD5 | raw file
  1#!/usr/bin/env python
  2"""\
  3@file simperf_proc_interface.py
  4@brief Utility to extract log messages from *.<pid>.llsd files containing performance statistics.
  5
  6$LicenseInfo:firstyear=2008&license=mit$
  7
  8Copyright (c) 2008-2009, Linden Research, Inc.
  9
 10Permission is hereby granted, free of charge, to any person obtaining a copy
 11of this software and associated documentation files (the "Software"), to deal
 12in the Software without restriction, including without limitation the rights
 13to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 14copies of the Software, and to permit persons to whom the Software is
 15furnished to do so, subject to the following conditions:
 16
 17The above copyright notice and this permission notice shall be included in
 18all copies or substantial portions of the Software.
 19
 20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 26THE SOFTWARE.
 27$/LicenseInfo$
 28"""
 29
 30# ----------------------------------------------------
 31# Utility to extract log messages from *.<pid>.llsd
 32# files that contain performance statistics.
 33
 34# ----------------------------------------------------
 35import sys, os
 36
 37if os.path.exists("setup-path.py"):
 38    execfile("setup-path.py")
 39
 40from indra.base import llsd
 41
 42DEFAULT_PATH="/dev/shm/simperf/"
 43
 44
 45# ----------------------------------------------------
 46# Pull out the stats and return a single document
 47def parse_logfile(filename, target_column=None, verbose=False):
 48    full_doc = []
 49    # Open source temp log file.  Let exceptions percolate up.
 50    sourcefile = open( filename,'r')
 51        
 52    if verbose:
 53        print "Reading " + filename  
 54    
 55    # Parse and output all lines from the temp file
 56    for line in sourcefile.xreadlines():
 57        partial_doc = llsd.parse(line)
 58        if partial_doc is not None:
 59            if target_column is None:
 60                full_doc.append(partial_doc)
 61            else:
 62                trim_doc = { target_column: partial_doc[target_column] }
 63                if target_column != "fps":
 64                    trim_doc[ 'fps' ] = partial_doc[ 'fps' ]
 65                trim_doc[ '/total_time' ] = partial_doc[ '/total_time' ]
 66                trim_doc[ 'utc_time' ] = partial_doc[ 'utc_time' ]
 67                full_doc.append(trim_doc)
 68
 69    sourcefile.close()
 70    return full_doc
 71
 72# Extract just the meta info line, and the timestamp of the first/last frame entry.
 73def parse_logfile_info(filename, verbose=False):
 74    # Open source temp log file.  Let exceptions percolate up.
 75    sourcefile = open(filename, 'rU') # U is to open with Universal newline support
 76        
 77    if verbose:
 78        print "Reading " + filename  
 79
 80    # The first line is the meta info line.
 81    info_line = sourcefile.readline()
 82    if not info_line:
 83        sourcefile.close()
 84        return None
 85
 86    # The rest of the lines are frames.  Read the first and last to get the time range.
 87    info = llsd.parse( info_line )
 88    info['start_time'] = None
 89    info['end_time'] = None
 90    first_frame = sourcefile.readline()
 91    if first_frame:
 92        try:
 93            info['start_time'] = int(llsd.parse(first_frame)['timestamp'])
 94        except:
 95            pass
 96
 97    # Read the file backwards to find the last two lines.
 98    sourcefile.seek(0, 2)
 99    file_size = sourcefile.tell()
100    offset = 1024
101    num_attempts = 0
102    end_time = None
103    if file_size < offset:
104        offset = file_size
105    while 1:
106        sourcefile.seek(-1*offset, 2)
107        read_str = sourcefile.read(offset)
108        # Remove newline at the end
109        if read_str[offset - 1] == '\n':
110            read_str = read_str[0:-1]
111        lines = read_str.split('\n')
112        full_line = None
113        if len(lines) > 2:  # Got two line
114            try:
115                end_time = llsd.parse(lines[-1])['timestamp']
116            except:
117                # We couldn't parse this line.  Try once more.
118                try:
119                    end_time = llsd.parse(lines[-2])['timestamp']
120                except:
121                    # Nope.  Just move on.
122                    pass
123            break
124        if len(read_str) == file_size:   # Reached the beginning
125            break
126        offset += 1024
127
128    info['end_time'] = int(end_time)
129
130    sourcefile.close()
131    return info
132    
133
134def parse_proc_filename(filename):
135    try:
136        name_as_list = filename.split(".")
137        cur_stat_type = name_as_list[0].split("_")[0]
138        cur_pid = name_as_list[1]
139    except IndexError, ValueError:
140        return (None, None)
141    return (cur_pid, cur_stat_type)
142
143# ----------------------------------------------------
144def get_simstats_list(path=None):
145    """ Return stats (pid, type) listed in <type>_proc.<pid>.llsd """
146    if path is None:
147        path = DEFAULT_PATH
148    simstats_list = []
149    for file_name in os.listdir(path):
150        if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd":
151            simstats_info = parse_logfile_info(path + file_name)
152            if simstats_info is not None:
153                simstats_list.append(simstats_info)
154    return simstats_list
155
156def get_log_info_list(pid=None, stat_type=None, path=None, target_column=None, verbose=False):
157    """ Return data from all llsd files matching the pid and stat type """
158    if path is None:
159        path = DEFAULT_PATH
160    log_info_list = {}
161    for file_name in os.listdir ( path ):
162        if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd":
163            (cur_pid, cur_stat_type) = parse_proc_filename(file_name)
164            if cur_pid is None:
165                continue
166            if pid is not None and pid != cur_pid:
167                continue
168            if stat_type is not None and stat_type != cur_stat_type:
169                continue
170            log_info_list[cur_pid] = parse_logfile(path + file_name, target_column, verbose)
171    return log_info_list
172
173def delete_simstats_files(pid=None, stat_type=None, path=None):
174    """ Delete *.<pid>.llsd files """
175    if path is None:
176        path = DEFAULT_PATH
177    del_list = []
178    for file_name in os.listdir(path):
179        if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd":
180            (cur_pid, cur_stat_type) = parse_proc_filename(file_name)
181            if cur_pid is None:
182                continue
183            if pid is not None and pid != cur_pid:
184                continue
185            if stat_type is not None and stat_type != cur_stat_type:
186                continue
187            del_list.append(cur_pid)
188            # Allow delete related exceptions to percolate up if this fails.
189            os.unlink(os.path.join(DEFAULT_PATH, file_name))
190    return del_list
191