############################################################
'''
    testForks.py
    Written by: Brian O'Dell, Spetember 2017

    A program to run each program a 500 times per thread count.
    Then uses the data collected to make graphs and tables that
    are useful to evaluate the programs running time.
'''
############################################################

from subprocess import *
from numba import jit
import numpy as np
import csv as csv
import pandas as pd
from pandas.plotting import table
import matplotlib.pyplot as plt

'''
    Call the C program multiple times with variable arguments to gather data
    The name of the executable should exist before running
'''
@jit
def doCount(name):
    j = 0
    while (j < 1025):
        for i in range(0,501):
            call([name,"-t",str(j), "-w"])
        if (j == 0):
            j = 1

        else:
            j = 2*j;

'''
    Turn the data into something meaningful.
    Takes all the data gets the average and standard deviation for each
    number of threads. Then plots a graph based on it. Also, makes
    a csv with the avg and stddev
'''
@jit
def exportData(name):
    DF = pd.read_csv("data/"+name+".csv")
    f = {'ExecTime':['mean','std']}

    #group by the number of threads in the csv and
    #apply the mean and standard deviation functions to the groups
    avgDF = DF.groupby('NumThreads').agg(f)
    avgTable = DF.groupby('NumThreads', as_index=False).agg(f)

    #When the data csv was saved we used 0 to indicate serial execution
    #this was so the rows would be in numerical order instead of Alphabetical
    #Now rename index 0 to Serial to be an accurate representation
    indexList = avgDF.index.tolist()
    indexList[0] = 'Serial'
    avgDF.index = indexList

    #make the bar chart and set the axes
    avgPlot = avgDF.plot(kind='bar',
                 title=('Run Times Using '+ name), legend='False', figsize=(15,8))
    avgPlot.set_xlabel("Number of Forks")
    avgPlot.set_ylabel("Run Time (seconds)")

    #put the data values on top of the bars for clarity
    avgPlot.legend(['mean','std deviation'])
    for p in avgPlot.patches:
        avgPlot.annotate((str(p.get_height())[:6]),
                  (p.get_x()-.01, p.get_height()), fontsize=9)

    #save the files we need
    plt.savefig('data/'+name+'Graph.png')
    avgTable.to_csv('data/'+name+'Table.csv', index=False, encoding='utf-8')


def main():
    doCount("./forkedSemaphor")
    doCount("./forkedPrivateCount")
    doCount("./forkedPrivateCount32")
    exportData("forkedSemaphor")
    exportData("forkedPrivateCount")
    exportData("forkedPrivateCount32")

if __name__ == '__main__':
    main()
