// class methods // Reads each line where there are metrics, creates a process object and adds it to the objects collection public List <PidProcessGroup> GetProcessMetrics() { // we need to keep track of blocks of metrics so that we know which metrics to group together. bool blockIsFirst = true; PidProcessGroup pidProcessGroup = new PidProcessGroup(); List <PidProcessGroup> processes = new List <PidProcessGroup>(); DateTimeUtility utility = new DateTimeUtility(); string emptyLinePattern = "^\\s*$"; string splitPattern = "\\s+"; Regex rgxEmptyLine = new Regex(emptyLinePattern); Regex rgxSplitLine = new Regex(splitPattern); var rgxTime = new Regex("^ *([0-2][0-9]:[0-2][0-9]:[0-2][0-9] ?[AaPp]?[Mm]?|[0-9]+)"); // starting at the first line where # appears for (int i = 2; i <= FileContents.Count - 1;) { if (FileContents[i].StartsWith("#")) { // if not the first block on first iteration, we add the complete metric group to the larger collection "processes" if (!blockIsFirst) { processes.Add(pidProcessGroup); } // if it is first iteration, we need to check and flip it to false so that future iterations will add to larger collection "processes" if (blockIsFirst) { blockIsFirst = false; } var thisProcessLine = FileContents[i + 1]; var match = rgxTime.Match(thisProcessLine); if (!match.Success) { throw new ApplicationException("Invalid pidstat.perf format"); } // reads the line timestamp, converts it from ephoc/unix time string thisTimeStamp = utility.GetTimeStamp(match.Value); // add the current line position to the block count array. We will use this to spin off multiple threads for processing the pid stat file BlockCount.Add(i + 1); i++; // we create the process group which groups by timestamp pidProcessGroup = new PidProcessGroup() { TimeStamp = thisTimeStamp }; } // just skip empty lines and increment to the next line else if (rgxEmptyLine.IsMatch(FileContents[i])) { i++; } else { var line = FileContents[i]; var match = rgxTime.Match(line); if (!match.Success) { throw new ApplicationException("Invalid pidstat.perf format"); } var subline = line.Substring(match.Length); // takes the value of the current line and splits on whitespace string[] thisProcessLine = rgxSplitLine.Split(subline); // reads the line timestamp, converts it from ephoc/unix time string thisTimeStamp = utility.GetTimeStamp(match.Value); // reads this line's pid int thisPid = Convert.ToInt32(thisProcessLine[2]); // reads this lines process name string thisProcessName = thisProcessLine[thisProcessLine.Length - 1]; // declares a new array so that we can populate this array with metrics with array.copy string[] theseMetrics = new string[MetricCount]; // copies the metrics from the current line to theseMetrics array. We need to do this since we split the line to get other metrics. Array.Copy(thisProcessLine, 3, theseMetrics, 0, MetricCount); // create a new process object and set its properties from the vairables we declared above PidProcess process = new PidProcess() { TimeStamp = thisTimeStamp, Pid = thisPid, ProcessName = thisProcessName, Metrics = theseMetrics }; // we need to filter out what gets collected based on the PidFilter in the config file. if (ConfigValues.PidStatFilter.Count() != -1 && ConfigValues.PidStatFilter.Contains(process.ProcessName)) { // once we are done generating the process object, we add the object to the collection of processes pidProcessGroup.GroupMetrics.Add(process); } // if there are no filters, we need to add everything if (ConfigValues.PidStatFilter[0] == "" || ConfigValues.PidStatFilter[0] == "false") { // once we are done generating the process object, we add the object to the collection of processes pidProcessGroup.GroupMetrics.Add(process); } i++; } } return(processes); }