function profreport(varargin)
%PROFREPORT MATLAB Profiler Report.
%   PROFREPORT(BASENAME,INFO) generates a report in HTML
%   format that summarizes MATLAB function call statistics
%   logged by the MATLAB Profiler.  PROFREPORT then displays
%   the report in your web browser.  BASENAME is the base
%   filename used to save the report.  Because the HTML report
%   consists of several different files, BASENAME should not
%   have an extension.  INFO is the Profiler information
%   structure returned by the command INFO = PROFILE('info').
%
%   PROFREPORT(BASENAME) generates the report using the
%   current Profiler statistics.
%
%   PROFREPORT(INFO) generates the report from the specified
%   INFO structure using a temporary filename.  The temporary
%   filename is generated using TEMPNAME.
%
%   PROFREPORT generates the report using the current Profiler
%   statistics and using a temporary filename.
%
%   Calling PROFREPORT suspends the MATLAB Profiler.
%
%   See also PROFILE.

%   Steven L. Eddins
%   Copyright (c) 1984-98 by The MathWorks, Inc.
%   $Revision: 1.8 $  $Date: 1998/10/02 16:18:19 $

profile off

[fname,structArray,history,clockPrec,msg] = ParseInputs(varargin{:});
if (~isempty(msg))
    error(msg);
end

if (isempty(structArray))
    error('Empty function log');
end

% Preprocess the function structure array.
structArray = MungeNames(structArray);
structArray = ComputeTimes(structArray);

[path,name,ext,ver] = fileparts(fname);
if (isempty(path))
    path = pwd;
end
frameName = [name '.html'];
contentsName = [name '_contents' '.html'];
summaryName = [name '_summary' '.html'];
detailsName = [name '_details' '.html'];
if (~isempty(history))
    if ((size(history,2)/2) > 500)
        qstr = sprintf('Because there are %d recorded function calls, generating the history report may take a long time.  Do you wish to generate the history report anyway?', floor(size(history,2)/2));
        result = questdlg(qstr);
        if (strcmp(result, 'Yes'))
            historyName = [name '_history' '.html'];
            
        elseif (strcmp(result, 'No'))
            historyName = '';
            
        elseif (strcmp(result, 'Cancel'))
            return;
        end
    else
        historyName = [name '_history' '.html'];
    end
else
    historyName = '';
end
    
PrintHTMLFrames(path, frameName, contentsName, summaryName);
PrintHTMLContentsFrame(path, contentsName, summaryName, ...
                detailsName, historyName);
PrintHTMLSummaryFrame(path, summaryName, detailsName, ...
                structArray, clockPrec);
PrintHTMLFunctionsFrame(path, detailsName, structArray, clockPrec);
if (~isempty(historyName))
    PrintHTMLHistoryFrame(path, historyName, detailsName, ...
                    history, structArray);
end
    
status = web(fullfile(path,frameName));
switch status
case 0
    % no action required
case 1
    warning('Report saved, but could not find web browser');
case 2
    warning('Report saved, but could not launch web browser');
otherwise
    % unknown status code from web
end

%%%
%%% PrintHTMLFrames
%%%
function PrintHTMLFrames(path, frameName, contentsName, summaryName)
% Prints the top-level HTML document, which contains the frameset tags.

fid = fopen(fullfile(path,frameName),'wt');
if (fid < 0)
    error('Error opening report file for writing');
end
fprintf(fid, '<html> \n');

fprintf(fid, '<script language="JavaScript">\n');
fprintf(fid, '        setTimeout ("forceToTop()", 0);\n');
fprintf(fid, '        function forceToTop() {\n');
fprintf(fid, '                if (self != top) {\n');
fprintf(fid, '                     top.location = document.location;\n');
fprintf(fid, '                }\n');
fprintf(fid, '        }\n');
fprintf(fid, '</script>\n');

fprintf(fid, '<head> \n');
fprintf(fid, '<title>MATLAB Profiler Report</title>\n');
fprintf(fid, '</head>\n');

fprintf(fid, '<frameset rows="50,*">\n');
fprintf(fid, '   <frame name="Frame 1" src="%s" scrolling="auto"> \n', ...
                contentsName);
fprintf(fid, '   <frame name="Frame 2" src="%s" scrolling="auto"> \n', ...
                summaryName);
fprintf(fid, '</frameset> \n');

fprintf(fid, '<body> \n');
fprintf(fid, '</body> \n');
fprintf(fid, '</html> \n');
fclose(fid);

%%%
%%% PrintHTMLContentsFrame
%%%
function PrintHTMLContentsFrame(path, contentsName, summaryName, detailsName, historyName)
% Prints the navigation frame.

fid = fopen(fullfile(path,contentsName),'wt');
if (fid < 0)
    error('Error opening report file for writing');
end
fprintf(fid, '<html> \n');
fprintf(fid, '<head> \n');
fprintf(fid, '</head>\n');

fprintf(fid, '<body bgcolor="#FFF7DE" link="#247B2B" vlink="#247B2B" > \n\n');
fprintf(fid, '<a href="%s" target="Frame 2">Summary</a>\n', summaryName);
fprintf(fid, '&nbsp;|&nbsp; <a href="%s" target="Frame 2">Function Details</a>\n', ...
                detailsName);
if (~isempty(historyName))
    fprintf(fid, '&nbsp;|&nbsp; <a href="%s" target="Frame 2">Function Call History</a>\n', ...
                    historyName);
end
fprintf(fid, '</body>\n');
fprintf(fid, '</html> \n');
fclose(fid);

%%%
%%% PrintHTMLSummaryFrame
%%%
function PrintHTMLSummaryFrame(path, summaryName, detailsName, structArray, clockPrec)
% Prints the summary frame

fid = fopen(fullfile(path, summaryName), 'wt');
if (fid < 0)
    error('Could not open report file for writing.');
end

fprintf(fid, '<html>\n');
fprintf(fid, '<head>\n');
fprintf(fid, '</head>\n');
fprintf(fid, '<body bgcolor="#FFF7DE" link="#247B2B" vlink="#247B2B" > \n\n');
fprintf(fid, '<h1>MATLAB Profile Report:  Summary</h1>\n');

fprintf(fid, '<p><em> Report generated %s </em></p>\n', datestr(now));

totalTime = sum([structArray.SelfTime]);
counts = CountFuncs(structArray);

fprintf(fid, '<table>\n');
fprintf(fid, '<tr> <td> Total recorded time: </td>\n');
fprintf(fid, '<td align="right"> %6.2f&nbsp;s </td> </tr>\n', totalTime);

if (counts.NumMfunctions > 0)
    fprintf(fid, '<tr> <td> Number of M-functions: </td>\n');
    fprintf(fid, '<td align="right"> %d </td> </tr>\n', ...
            counts.NumMfunctions);
end

if (counts.NumMsubfunctions > 0)
    fprintf(fid, '<tr> <td> Number of M-subfunctions: </td>\n');
    fprintf(fid, '<td align="right"> %d </td> </tr>\n', ...
            counts.NumMsubfunctions);
end

if (counts.NumMscripts > 0)
    fprintf(fid, '<tr> <td> Number of M-scripts: </td>\n');
    fprintf(fid, '<td align="right"> %d </td> </tr>\n', ...
            counts.NumMscripts);
end

if (counts.NumMEXfunctions > 0)
    fprintf(fid, '<tr> <td> Number of MEX-functions: </td>\n');
    fprintf(fid, '<td align="right"> %d </td> </tr>\n', ...
            counts.NumMEXfunctions);
end

if (counts.NumBuiltins > 0)
    fprintf(fid, '<tr> <td> Number of builtins: </td>\n');
    fprintf(fid, '<td align="right"> %d </td> </tr>\n', ...
            counts.NumBuiltins);
end

fprintf(fid, '<tr> <td> Clock precision: </td>\n');
fprintf(fid, '<td align="right"> %5.3f&nbsp;s </td> </tr>\n', clockPrec);
fprintf(fid, '</table>\n\n');

PrintHTMLFunctionList(fid, detailsName, structArray, clockPrec);

fprintf(fid, '</body>\n');
fprintf(fid, '</html>\n');

fclose(fid);

%%%
%%% PrintHTMLHistoryFrame
%%%
function PrintHTMLHistoryFrame(path, historyName, detailsName, history, structArray)
% Prints the history frame

fid = fopen(fullfile(path, historyName), 'wt');
if (fid < 0)
    error('Could not open report file for writing.');
end

wbHandle = waitbar(0,'Generating function call history report ...');

fprintf(fid, '<html>\n');
fprintf(fid, '<head>\n');
fprintf(fid, '</head>\n');
fprintf(fid, '<body bgcolor="#FFF7DE" link="#247B2B" vlink="#247B2B" > \n\n');
fprintf(fid, '<h1>MATLAB Profile Report:  Function Call History</h1>\n');

stackDepth = -1;
for k = 1:size(history,2)
    if (history(1,k) == 0)
        % Function is called
        stackDepth = stackDepth + 1;
        index = history(2,k);
        href = sprintf('%s#Fcn_%d', detailsName, index);
        spaces = ['<code>' repmat('&nbsp;&nbsp;',[1 stackDepth*2]) '</code>'];
        fprintf(fid, '<nobr>%s%s', spaces, ...
                        Link(FormatName(structArray(index).FunctionName),href));
        if (isempty(structArray(index).MfileName))
            fprintf(fid, '</nobr>');
        else
            fprintf(fid, '&nbsp;&nbsp;&nbsp;&nbsp;(%s)</nobr>', ...
                            FormatPath(structArray(index).MfileName));
        end
        fprintf(fid, '<br><br>\n');
        
    else
        stackDepth = stackDepth - 1;
    end
    
    if (mod(k,10) == 0)
        waitbar(k/size(history,2));
    end
end
    
fprintf(fid, '</body>\n');
fprintf(fid, '</html>\n');

fclose(fid);

close(wbHandle);

%%%
%%% Anchor
%%%
function out = Anchor(str,name)
% Turns a string into an HTML named anchor.

out = sprintf('<a name="%s"> %s </a>', name, str);

%%%
%%% PrintHTMLFunctionList
%%%
function PrintHTMLFunctionList(fid, detailsName, structArray, clockPrec)
% Print the list of functions in a table.

digits1 = ceil(-log10(clockPrec));
digits2 = digits1 + ceil(log10(max([structArray.NumCalls])));

[junk,sortedIdx] = sort([structArray.TotalTime]);
sortedIdx = sortedIdx(end:-1:1);

totalTime = sum([structArray.SelfTime]);
if (totalTime == 0)
    totalTime = eps;
end

fprintf(fid, '<h2> %s </h2> \n\n', Anchor('Function List', 'Function List'));

fprintf(fid, '<table border=1>\n');
fprintf(fid, '<th align=left> <small> Name </small> </th>\n');
fprintf(fid, '<th align=left colspan=2> <small> Time </small> </th>\n');
fprintf(fid, '<th align=left> <small> Calls </small> </th>\n');
fprintf(fid, '<th align=left> <small> Time/call </small> </th>\n');
fprintf(fid, '<th align=left colspan=2> <small> Self time </small> </th>\n');
fprintf(fid, '<th align=left> <small> Location </small> </th>\n');
fprintf(fid, '</tr>\n');

for k = 1:length(structArray)
    thisStruct = structArray(sortedIdx(k));
    href = sprintf('%s#Fcn_%d', detailsName, sortedIdx(k));
    
    fprintf(fid, '<tr>\n');

    fprintf(fid, '<td>%s</td> \n', ...
                    Link(FormatName(thisStruct.FunctionName),href));
    fprintf(fid, '<td align="right"> <small> %s </small> </td>\n', ...
            FormatTime(thisStruct.TotalTime, digits1));
    fprintf(fid, '<td align="right"> <small> %5.1f%% </small> </td>\n', ...
            thisStruct.TotalTime * 100 / totalTime);
    fprintf(fid, '<td align="right"> <small> %d </small> </td>\n', ...
            thisStruct.NumCalls);
    fprintf(fid, '<td align="right"> <small> %s </small> </td>\n', ...
            FormatTime(thisStruct.TotalTime / thisStruct.NumCalls, digits2));
    fprintf(fid, '<td align="right"> <small> %s </small> </td>\n', ...
            FormatTime(thisStruct.SelfTime, digits1));
    fprintf(fid, '<td align="right"> <small> %5.1f%% </small> </td>\n', ...
            thisStruct.SelfTime * 100 / totalTime);
    if (~isempty(thisStruct.MfileName))
        fprintf(fid, '<td> %s </td>\n', ...
                        FormatPath(thisStruct.MfileName));
    else
        fprintf(fid, '<td> <small> <em> builtin </em> </small> </td>\n');
    end
    
    fprintf(fid, '</tr>\n');
end

fprintf(fid, '</table>\n');

%%%
%%% Link
%%%
function out = Link(in,href)
% Turn a string into a cross-reference.

out = sprintf('<a href="%s">%s</a>', href, in);

%%%
%%% FormatName
%%%
function out = FormatName(name)
% Format a function name with the right color and font.

out = sprintf('<font color="#0000FF"><tt><b>%s</b></tt></font>', ...
                name);

%%%
%%% FormatTime
%%%
function out = FormatTime(seconds, digits)
% Format a time string with the right number of decimal places.

formatStr = sprintf('%%.%df', digits);
out = sprintf(formatStr, seconds);

%%%
%%% FormatPath
%%%
function out = FormatPath(pathStr)
% Format a path string as a file URL.

href = ['file://' pathStr];

out = sprintf('<tt><a href="%s">%s</a></tt>', href, pathStr);

%%%
%%% PrintHTMLFunctions
%%%
function PrintHTMLFunctionsFrame(path, detailsName, structArray, clockPrec)
% Print the Function Details frame.

fid = fopen(fullfile(path,detailsName), 'wt');
if (fid < 0)
    error('Could not open report file for writing.');
end

wbHandle = waitbar(0,'Generating function details report ...');

fprintf(fid, '<html>\n');
fprintf(fid, '<head>\n');
fprintf(fid, '</head>\n');
fprintf(fid, '<body bgcolor="#FFF7DE" link="#247B2B" vlink="#247B2B" > \n\n');

[junk,sortedIdx] = sort([structArray.TotalTime]);
sortedIdx = sortedIdx(end:-1:1);

totalTime = sum([structArray.SelfTime]);

fprintf(fid, '<h1>MATLAB Profile Report:  Function Details</h1>\n');

fprintf(fid, '<dl>\n');
for k = 1:length(structArray)
    PrintHTMLFunctionDetails(fid, structArray, sortedIdx(k), totalTime, clockPrec);
    waitbar(k/length(structArray));
end
fprintf(fid, '</dl>\n');

fprintf(fid, '</body>\n');
fprintf(fid, '</html>\n');

fclose(fid);

close(wbHandle);

%%%
%%% PrintHTMLFunctionDetails
%%%
function PrintHTMLFunctionDetails(fid, structArray, p, totalTime, clockPrec)
% Print the detailed report for a given function.

funcStruct = structArray(p);
refStr = sprintf('Fcn_%d', p);
formattedName = FormatName(funcStruct.FunctionName);
digits1 = ceil(-log10(clockPrec));
digits2 = digits1 + ceil(log10(max([structArray.NumCalls])));

fprintf(fid, '<dt>\n');
fprintf(fid, '<hr size=5 noshade>\n');
if (isempty(funcStruct.MfileName))
    fprintf(fid,'%s &nbsp;&nbsp;&nbsp;&nbsp;<em>builtin</em><br>\n', ...
                    Anchor(formattedName, refStr));
else
    fprintf(fid,'%s &nbsp;&nbsp;&nbsp;&nbsp;%s<br>\n', ...
                    Anchor(formattedName, refStr), ...
                    FormatPath(funcStruct.MfileName));
end

fprintf(fid, 'Time: %s s &nbsp;&nbsp; (%4.1f%%)<br>\n', ...
                FormatTime(funcStruct.TotalTime, digits1), ...
                100 * funcStruct.TotalTime / (max(totalTime, eps)));
fprintf(fid, 'Calls: %d <br>\n', funcStruct.NumCalls);
fprintf(fid, 'Self time: %s s &nbsp;&nbsp; (%4.1f%%)<br><br>\n', ...
                FormatTime(funcStruct.SelfTime, digits1), ...
                100 * funcStruct.TotalTime / (max(totalTime, eps)));

fprintf(fid, '<dd>\n');
fprintf(fid, '<table border=1>\n');
fprintf(fid, '<th align=left> <small> Function: </small> </th>\n');
fprintf(fid, '<th align=left colspan=2> <small> Time </small> </th>\n');
fprintf(fid, '<th align=left> <small> Calls </small> </th>\n');
fprintf(fid, '<th align=left> <small> Time/call </small> </th>\n');
fprintf(fid, '</tr>\n');

fprintf(fid, '<tr>\n');
fprintf(fid, '<td> %s </td>\n', formattedName);
fprintf(fid, '<td align=right> <small> %s </small> </td>\n', ...
                FormatTime(funcStruct.TotalTime, digits1));
fprintf(fid, '<td> &nbsp; </td>\n');
fprintf(fid, '<td align=right> <small> %d </small>\n', funcStruct.NumCalls);
fprintf(fid, '<td align=right> <small> %s </small> </td>\n', ...
                FormatTime(funcStruct.TotalTime / funcStruct.NumCalls, digits2));
fprintf(fid, '</tr>\n');

fprintf(fid, '<tr> <td colspan=5> &nbsp; </tr>\n');

fprintf(fid, '<tr> <td colspan=5> <small> <b>Parent functions:</b> </small> </td> </tr>\n');
if (length(funcStruct.Parents) == 0)
    fprintf(fid, '<tr> <td colspan=5> <small> <em> none </em> </small> </td> </tr> \n');
else
    for k = 1:length(funcStruct.Parents)
        href = sprintf('#Fcn_%d', funcStruct.Parents(k).Index);
        parentName = FormatName(structArray(funcStruct.Parents(k).Index).FunctionName);
        fprintf(fid, '<tr>\n');
        fprintf(fid, '<td colspan=3> %s </td>\n', Link(parentName,href));
        fprintf(fid, '<td align=right> <small> %d </small> </td>\n', ...
                        funcStruct.Parents(k).NumCalls);
        fprintf(fid, '<td> &nbsp; </td>\n');
        fprintf(fid, '<tr>\n');
    end
end

fprintf(fid, '<tr> <td colspan=5> &nbsp; </tr>\n');

fprintf(fid, '<tr> <td colspan=5> <small> <b>Child functions:</b> </small> </td> </tr>\n');
kids = funcStruct.Children;
if (length(kids) == 0)
    fprintf(fid, '<tr> <td colspan=5> <small> <em> none </em> </small> </td> </tr> \n');
else
    [junk,idx] = sort(-[kids.TotalTime]);
    kids = kids(idx);
    for k = 1:length(kids)
        href = sprintf('#Fcn_%d', kids(k).Index);
        childName = FormatName(structArray(kids(k).Index).FunctionName);
        fprintf(fid, '<tr>\n');
        fprintf(fid, '<td> %s </td>\n', Link(childName,href));
        fprintf(fid, '<td align=right> <small> %s </small> </td>\n', ...
                        FormatTime(kids(k).TotalTime, digits1));
        fprintf(fid, '<td align=right> <small> %4.1f%% </small> </td>\n', ...
                        100 * kids(k).TotalTime / max(funcStruct.TotalTime, eps));
        fprintf(fid, '<td align=right> <small> %d </small> </td>\n', ...
                        kids(k).NumCalls);
        fprintf(fid, '<td align=right> <small> %s </small> </td>\n', ...
                        FormatTime(kids(k).TotalTime / ...
                        kids(k).NumCalls, digits2));
        fprintf(fid, '<tr>\n');
    end
end
fprintf(fid, '</table><br><br>\n');

stats = LineStats(funcStruct);
if (~isempty(stats))
    totalLineTime = sum([stats{:,2}]);
    fprintf(fid, '%d%% of the total time in this function was spent on the following lines:<br><br>\n',...
                    floor(100 * totalLineTime / max(funcStruct.TotalRecursiveTime,eps)));
    fprintf(fid, '<table border=0> \n');
    for k = 1:size(stats,1)
        lineNum = stats{k,1};
        lineTime = stats{k,2};
        lineString = stats{k,3};
        
        if ((k > 1) & (lineNum > (stats{k-1,1} + 1)))
            fprintf(fid, '<tr> <td> &nbsp; </td> </tr> \n');
        end
        
        fprintf(fid, '<tr> \n');
        
        if (lineTime > 0)
            fprintf(fid, '<td align=right> <code> %s </code> </td>\n', ...
                            FormatTime(lineTime, digits1));
            fprintf(fid, '<td align=right> <code> %d%% </code> </td>\n', ...
                            round(100 * lineTime / ...
                            max(funcStruct.TotalRecursiveTime, eps)));
        else
            fprintf(fid, '<td> &nbsp; </td>\n');
            fprintf(fid, '<td> &nbsp; </td>\n');
        end
        
        fprintf(fid, '<td align=right> <code> %d:&nbsp; </code> </td>\n', ...
                        lineNum);
        % Replace tabs by 2 spaces, then replace spaces by
        % nonbreaking spaces.
        lineString = strrep(lineString,char(9),'  ');
        lineString = strrep(lineString,' ','&nbsp;');
        fprintf(fid, '<td> <code> <nobr> %s </nobr> </code> </td> %\n', ...
                                         lineString);
        
        fprintf(fid, '</tr> \n');
    end
    fprintf(fid, '</table>\n');
end

        

function counts = CountFuncs(structArray)
% Count the number of functions of each type.

counts.NumMfunctions = 0;
counts.NumMsubfunctions = 0;
counts.NumMscripts = 0;
counts.NumMEXfunctions = 0;
counts.NumBuiltins = 0;

for k = 1:length(structArray)
    switch structArray(k).Type
    case 'M-function'
        counts.NumMfunctions = counts.NumMfunctions + 1;
        
    case 'M-subfunction'
        counts.NumMsubfunctions = counts.NumMsubfunctions + 1;
        
    case 'M-script'
        counts.NumMscripts = counts.NumMscripts + 1;
        
    case 'MEX-function'
        counts.NumMEXfunctions = counts.NumMEXfunctions + 1;
        
    case 'Builtin-function'
        counts.NumBuiltins = counts.NumBuiltins + 1;
        
    otherwise
        % unrecognized type; ignore it
        
    end
end

function structArray = MungeNames(structArray)
% MATLAB stores names for private functions as the full path; strip
% out the path part.

s = ['private' filesep];

for k = 1:length(structArray)
    idx = findstr(s, structArray(k).FunctionName);
    if (~isempty(idx))
        structArray(k).FunctionName = structArray(k).FunctionName(idx(end) + ...
                        length(s):end);
    end
end

function newArray = ComputeTimes(structArray)
% Compute self time and total recursive time.

newArray = structArray;

for k = 1:length(newArray)
    childTime = 0;
    for p = 1:length(newArray(k).Children)
        childTime = childTime + newArray(k).Children(p).TotalTime;
    end
    newArray(k).TotalChildrenTime = childTime;
    newArray(k).SelfTime = newArray(k).TotalRecursiveTime - ...
            childTime;
end

%%%
%%% LineStats
%%%
function stats = LineStats(funcStruct)
% Return P-by-3 cell array.  First column is the line number.  Second column
% is the line time.  Third column is the line string.  P is the the number
% of lines accounting for 95% of the total time, or 10 lines, or the total
% number of lines in the file, whichever is smaller.

if (isempty(funcStruct.MfileName) | strcmp(funcStruct.Type, 'MEX-function'))
    stats = cell(0,3);
else
    
    % Check for P-file.
    if (strcmpi(funcStruct.MfileName(end-1:end), '.p'))
        funcStruct.MfileName = [funcStruct.MfileName(1:end-2) '.m'];
        fid = fopen(funcStruct.MfileName);
        if (fid < 0)
            stats = cell(0,3);
        end
    else
        fid = fopen(funcStruct.MfileName);
        if (fid < 0)
            error(sprintf('Could not open "%s".', funcStruct.MfileName));
        end
    end

    if (fid >= 0)
        comp = computer;
        newLine = sprintf('\n');
        stripChar = sprintf('\r');
        inMat = char(fread(fid, Inf, 'uchar'))';
        fclose(fid);
        % Check for the case where the last line does not end
        % with a line break.
        if (inMat(end) ~= newLine)
            inMat = [inMat newLine];
        end
        inMat(inMat == stripChar) = [];
        L = length(inMat);
        lineBreaks = [0 find(inMat == newLine)];
        
        timePerLine(funcStruct.ExecutedLines(:,1)) = funcStruct.ExecutedLines(:,3);
        timePerLine = timePerLine(:);
        totalTime = max(sum(timePerLine),eps);
        numInputLines = length(timePerLine);
        
        [bb, mfileIdx] = sort(timePerLine);
        bb = flipud(bb);
        mfileIdx = flipud(mfileIdx);
        
        % Report on the lines accounting for 95% of the total time, or 10
        % lines, or the total number of lines in the file, whichever
        % is smaller.
        numBusyLines = min(min(length(find((cumsum(bb)/max(totalTime,eps))>.95)), ...
                        10), numInputLines);
        bb = bb(1:numBusyLines);
        mfileIdx = mfileIdx(1:numBusyLines);
        
        %---------------------------------------------------------
        % Find the context lines, storing them in mfileLines.
        
        if (~isempty(mfileIdx))
            % Get rid of lines with no sample hits.
            mfileIdx(bb==0) = [];
            bb(bb==0) = [];
            
            mfileLines = max(1, [mfileIdx-1 ; mfileIdx ; mfileIdx+1]);
            
            % Remove out of range lines
            mfileLines((mfileLines < 1) | (mfileLines > numInputLines)) = [];
            
            mfileLines = sort(mfileLines);
            d = find(abs(diff(mfileLines))==0);
            mfileLines(d) = [];
        else
            mfileLines = [];
        end
        
        stats = cell(length(mfileLines), 3);
        for m = 1:length(mfileLines)
            nextLine = inMat(lineBreaks(mfileLines(m))+1:lineBreaks(mfileLines(m)+1)-1);
            k = find(mfileIdx == mfileLines(m));
            if (isempty(k))
                lineTime = 0;
            else
                lineTime = bb(k);
            end
            stats{m,1} = mfileLines(m);
            stats{m,2} = lineTime;
            stats{m,3} = nextLine;
        end
    end
end

function [fname,structArray,history,clockPrec,msg] = ParseInputs(varargin)

fname = '';
structArray = [];
history = [];
clockPrec = [];
msg = '';

msg = nargchk(0,2,nargin);
if (~isempty(msg))
    return;
end

if (nargin == 0)
    % PROFREPORT
    fname = tempname;
    info = profile('info');
    
elseif (nargin == 1)
    if (ischar(varargin{1}))
        % PROFREPORT(BASENAME)
        fname = varargin{1};
        info = profile('info');
        
    elseif (isstruct(varargin{1}))
        % PROFREPORT(INFO)
        fname = tempname;
        info = varargin{1};
        
    else
        msg = 'First input to PROFREPORT must be INFO struct or BASENAME string';
        return
    end
    
elseif (nargin == 2)
    % PROFREPORT(BASENAME,INFO)
    if (~ischar(varargin{1}))
        msg = 'Expected BASENAME string as first input';
        return
    end
    if (~isstruct(varargin{2}))
        msg = 'Expected INFO struct as second input';
        return
    end
    
    fname = varargin{1};
    info = varargin{2};
    
end

structArray = info.FunctionTable;
history = info.FunctionHistory;
clockPrec = info.ClockPrecision;
