import java.io.*;
import java.util.*;

public class Prof
{

    // cat /tmp/profile.log | arm-elf-addr2line -e main.out -fi > /tmp/profile.dat

    static class Line implements Comparable<Line>
    {
	int    lineNumber;
	int    samples;

	public Line(int lineNumber)
	{
	    this.lineNumber = lineNumber;
	}

	// sort by line number
	public int compareTo(Line l)
	{
	    return lineNumber - l.lineNumber;
	}
    }

    static class Function implements Comparable<Function>
    {
	String file;
	String name;
	int    samples;
	HashMap<Integer, Line> lines = new HashMap<Integer, Line>();

	public Function(String file, String name)
	{
	    this.file = file;
	    this.name = name;
	}

	public int compareTo(Function f)
	{
	    return f.samples - samples;
	}

	public void sampleLine(int lineNumber)
	{
	    Line line = lines.get(lineNumber);
	    if (line == null) {
		line = new Line(lineNumber);
		lines.put(lineNumber, line);
	    }

	    line.samples++;
	    samples++;
	}

	public void output(int totalSamples)
	{
	    ArrayList<Line> ls = new ArrayList<Line>(lines.values());
	    Collections.sort(ls);

	    int context = 5;
	    int low = ls.get(0).lineNumber - context;
	    if (low < 0)
		low = 0;
	    int high = ls.get(ls.size()-1).lineNumber + context;

	    int next = 0;
	    for (int i = low; i <= high; i++) {
		Line line = null;

		if (next < lines.size())
		    line = ls.get(next);

		double percent = 0;

		if (line != null && line.lineNumber == i) {
		    percent = 100.0*line.samples/totalSamples;
		    next++;
		}

		System.out.printf("             %6.5f  %5d: %s\n", 
				  percent, i, db.getLine(file, i));

	    }

	    System.out.printf("\n");
	}

    }

    static class LineDatabase
    {
	HashMap<String, ArrayList<String>> files = new HashMap<String, ArrayList<String>>();
	ArrayList<String> searchPath = new ArrayList<String>();

	public LineDatabase()
	{
	    addPath(".");
	    addPath("/");
	}

	public void addPath(String path)
	{
	    searchPath.add(path);
	}

	void loadFile(String file)
	{
	    ArrayList<String> lines = new ArrayList<String>();
	    String path = null;

	    for (int i = 0; i < searchPath.size(); i++) {
		path = searchPath.get(i) + "/" + file;
		File f = new File(path);
		if (f.exists())
		    break;
	    }

	    try {
		BufferedReader ins = new BufferedReader(new FileReader(path));
		String line;

		while ((line = ins.readLine())!=null) {
		    lines.add(line);
		}

		ins.close();
		files.put(file, lines);
	    } catch (IOException ex) {
		//		System.out.println("ex: "+ex);
	    }
	}

	public String getLine(String file, int line)
	{
	    line--; // adjust for zero-indexing

	    ArrayList<String> lines = files.get(file);
	    if (lines == null) {
		loadFile(file);
		lines = files.get(file);
	    }

	    if (lines == null || line >= lines.size())
		return "";

	    return lines.get(line);
	}
    }

    static LineDatabase db = new LineDatabase();

    public static void main(String args[])
    {
	for (int i = 1; i < args.length; i++)
	    db.addPath(args[i]);

	HashMap<String, Function> functions = new HashMap<String, Function>();

	try {
	    BufferedReader ins = new BufferedReader(new FileReader(args[0]));

	    int totalSamples = 0;

	    while (true)
		{
		    String functionName = ins.readLine();
		    String fileline = ins.readLine();

		    if (functionName == null || fileline==null)
			break;
		    
		    int idx = fileline.indexOf(':');
		    String file = fileline.substring(0, idx);
		    int lineNumber = Integer.parseInt(fileline.substring(idx+1));

		    Function f = functions.get(functionName);
		    if (f == null) {
			f = new Function(file, functionName);
			functions.put(functionName, f);
		    }

		    f.sampleLine(lineNumber);
		    totalSamples++;
		}
	    
	    System.out.printf("%d samples, each samples is %6.5f%%\n\n", totalSamples, 100.0/totalSamples);

	    ArrayList<Function> fs = new ArrayList<Function>(functions.values());
	    Collections.sort(fs);
	    
	    for (int i = 0; i < fs.size(); i++) {
		Function f = fs.get(i);
		System.out.printf("%6.3f %s\n", f.samples*100.0/totalSamples, f.name);
		f.output(totalSamples);
	    }

	    System.out.printf("Total hits: %d\n", totalSamples);

	} catch (IOException ex) {
	    System.out.println("ioex: "+ex);

	}
    }
}
