410 lines
13 KiB
C++
410 lines
13 KiB
C++
#include <iostream>
|
|
#include <iterator>
|
|
#include <unordered_map>
|
|
#include <fstream>
|
|
#include <cstdio>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <getopt.h>
|
|
#include <algorithm>
|
|
#include <iomanip>
|
|
#include <chrono>
|
|
#include <thread>
|
|
|
|
|
|
using namespace std;
|
|
using namespace std::chrono;
|
|
const int BUFFER_SIZE = 2048;
|
|
|
|
|
|
inline string join(vector<string> const &strings, string delim)
|
|
{
|
|
stringstream ss;
|
|
string res = "";
|
|
copy(strings.begin(), strings.end(),
|
|
ostream_iterator<string>(ss, delim.c_str()));
|
|
|
|
res = ss.str();
|
|
res.pop_back();
|
|
return res;
|
|
}
|
|
|
|
inline vector<string> tokenize(string s, string delimiter = " ")
|
|
{
|
|
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
|
|
string token;
|
|
vector<string> res;
|
|
|
|
while ((pos_end = s.find(delimiter, pos_start)) != string::npos) {
|
|
token = s.substr (pos_start, pos_end - pos_start);
|
|
pos_start = pos_end + delim_len;
|
|
res.push_back (token);
|
|
}
|
|
|
|
res.push_back (s.substr (pos_start));
|
|
|
|
return res;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
ios::sync_with_stdio(false);
|
|
cin.tie(NULL);
|
|
|
|
//may return 0 when not able to detect
|
|
// const unsigned int max_thread_count = std::thread::hardware_concurrency();
|
|
// unsigned int thread_count = max_thread_count - 1;
|
|
|
|
string filename = "";
|
|
int append = 1;
|
|
int crush_all = 0;
|
|
int debug_mode = 0;
|
|
vector<string> testnames;
|
|
|
|
int c;
|
|
bool no_opt = true;
|
|
while ((c = getopt(argc, argv, "hf:rdt:x")) != -1) {
|
|
switch (c) {
|
|
case 'h':
|
|
cout << "Usage: " << argv[0] << " -f <filename> [-r <truncate>] [-t <testnames>] [-h]\n";
|
|
return 0;
|
|
case 'f':
|
|
filename = optarg;
|
|
break;
|
|
case 't':
|
|
optind--;
|
|
for( ;optind < argc && *argv[optind] != '-'; optind++){
|
|
testnames.push_back(argv[optind] );
|
|
}
|
|
break;
|
|
case 'r':
|
|
append = 0;
|
|
break;
|
|
case 'x':
|
|
crush_all = 1;
|
|
break;
|
|
case 'd':
|
|
debug_mode = 1;
|
|
break;
|
|
default:
|
|
cout << "Invalid option. Use -h for help.\n";
|
|
return 1;
|
|
}
|
|
no_opt = false;
|
|
}
|
|
|
|
if (no_opt == true) {
|
|
vector<string> prog_path = tokenize(argv[0], "\\");
|
|
string prog_name = prog_path.back();
|
|
cout << "Usage: " << prog_name << " -f <filename> [-r <truncate>] [-t <testnames>] [-h]\n";
|
|
|
|
cout << "\tOptions:\n";
|
|
cout << "\t\t-f => Specify .datalog file name\n";
|
|
cout << "\t\t-t => Specify tests to be extracted seprated by space\n";
|
|
cout << "\t\t-r => Truncate or replace generated files (default is append)\n";
|
|
cout << "\t\t-x => Exract all tests, overrides tests specified in -t\n\n";
|
|
return 1;
|
|
}
|
|
if (filename == "") {
|
|
return 0;
|
|
}
|
|
|
|
unordered_map<string, int> has_header;
|
|
unordered_map<string, ofstream> FILE_HANDLE;
|
|
unordered_map<
|
|
string,
|
|
vector<vector<string>>
|
|
> hash_buff;
|
|
|
|
for(auto& name : testnames) {
|
|
has_header[name] = 0;
|
|
hash_buff[name].clear();
|
|
if (append == 1) {
|
|
FILE_HANDLE[name].open(name + ".csv", ios::app);
|
|
} else {
|
|
FILE_HANDLE[name].open(name + ".csv", ios::out | ios::trunc);
|
|
}
|
|
}
|
|
|
|
ifstream file_input;
|
|
|
|
file_input = ifstream(filename);
|
|
stringstream buffer;
|
|
buffer << file_input.rdbuf();
|
|
vector <string> m_vec_file;
|
|
m_vec_file = tokenize(buffer.str(), "\n");
|
|
|
|
|
|
if (!file_input) {
|
|
cerr << "Could not open input file!\n";
|
|
return 1;
|
|
}
|
|
|
|
|
|
string testname = "";
|
|
string productname = "prodname";
|
|
string programrev = "99.99";
|
|
string operatorlotname = "operlotname";
|
|
string lotname = "0C00000";
|
|
string wafer = "99";
|
|
string temperature = "99";
|
|
string testsite;
|
|
string x_coord;
|
|
string y_coord;
|
|
|
|
unordered_map<string, int>
|
|
testcollookup = { {"TNAME", 9},
|
|
{"VCC", 10},
|
|
{"SUPPLIES", 11},
|
|
{"VALUE", 13},
|
|
{"INT", 14},
|
|
{"LOG_INT", 14},
|
|
{"RESULTS", 15},
|
|
{"PATTERN", 16},
|
|
{"STATE", 17},
|
|
{"NUM", 18},
|
|
{"CONDITION1", 19},
|
|
{"CONDITION2", 20},
|
|
{"CONDITION3", 21},
|
|
{"TEXT", 22}
|
|
};
|
|
int max_col = numeric_limits<int>::min();
|
|
for (const auto& value : testcollookup) {
|
|
if (value.second > max_col) {
|
|
max_col = value.second;
|
|
}
|
|
}
|
|
|
|
|
|
vector<string> testheader;
|
|
vector<string> testdetails;
|
|
|
|
string last_match;
|
|
string line;
|
|
|
|
|
|
auto time_start = steady_clock::now();
|
|
long line_pos = 1;
|
|
long max_line_pos = m_vec_file.size();
|
|
|
|
string m_filename = (tokenize(filename, "\\")).back();
|
|
|
|
|
|
unsigned int part_size = m_vec_file.size() / 2; //thread_count;
|
|
// std::cout << "Part Size: " << part_size << " lines\n";
|
|
|
|
for (; part_size < m_vec_file.size(); ++part_size) {
|
|
vector<string> part_split_line;
|
|
string part_line = m_vec_file[part_size];
|
|
|
|
part_split_line = tokenize(part_line);
|
|
if (part_split_line[0] == "#START_DEVICE") {
|
|
break;
|
|
}
|
|
|
|
}
|
|
// std::cout << m_vec_file[part_size] << "\n";
|
|
for (unsigned int ctr = 0; ctr < m_vec_file.size(); ++ctr) {
|
|
line = m_vec_file[ctr];
|
|
if ((int(line_pos) % 500 == 0) || (line_pos == max_line_pos)) {
|
|
std::cout << "\r File: " << m_filename << " [" << fixed << setprecision(3) << (100* (float)line_pos / (float)max_line_pos) << "%] ";
|
|
}
|
|
vector<string> split_line;
|
|
string match1 = "99";
|
|
string match2 = "99";
|
|
|
|
split_line = tokenize(line);
|
|
|
|
if (split_line.size()>0) {
|
|
match1 = split_line.at(0);
|
|
|
|
if (split_line.size()>1) {
|
|
match2 = split_line.at(1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (match1 == "#PRODUCT") {
|
|
productname = match2;
|
|
last_match = "PRODUCT";
|
|
} else if (match1 == "#REV") {
|
|
programrev = match2;
|
|
last_match = "REV";
|
|
} else if (match1 == "#OPER_LOT_ID") {
|
|
operatorlotname = match2;
|
|
last_match = "OPER_LOT_ID";
|
|
} else if (match1 == "#LOT") {
|
|
if (match2 != "99") {
|
|
string lotname_temp = match2;
|
|
if (lotname_temp.length() > 6) {
|
|
lotname = lotname_temp.substr(0, 7);
|
|
} else {
|
|
lotname = lotname_temp;
|
|
}
|
|
last_match = "LOT";
|
|
}
|
|
} else if (match1 == "#WAFER") {
|
|
wafer = match2;
|
|
last_match = "WAFER";
|
|
} else if (match1 == "#LOTWAFER") {
|
|
vector<string> lotwafer_info = tokenize(match2, "_");
|
|
wafer = lotwafer_info.at(2);
|
|
lotname = lotwafer_info.at(1);
|
|
last_match = "LOTWAFER";
|
|
} else if (match1 == "#TEMP") {
|
|
temperature = match2;
|
|
last_match = "TEMP";
|
|
} else if (match1 == "#START_DEVICE") {
|
|
|
|
last_match = "START_DEVICE";
|
|
} else if (match1 == "#DIE_X") {
|
|
x_coord = match2;
|
|
last_match = "DIE_X";
|
|
} else if (match1 == "#DIE_Y") {
|
|
y_coord = match2;
|
|
last_match = "DIE_Y";
|
|
} else if (match1 == "#SITE") {
|
|
testsite = match2;
|
|
last_match = "SITE";
|
|
} else if (match1 == "TNAME") {
|
|
|
|
stringstream ss(line);
|
|
string word;
|
|
testheader.clear();
|
|
while (ss >> word) { // Extract word from the stream.
|
|
testheader.push_back(word);
|
|
}
|
|
|
|
|
|
last_match = "TNAME";
|
|
} else if (match1 == "bin_result") {
|
|
// cout << "[" << match1 << "]\n";
|
|
for ( auto &my_pair : hash_buff ) {
|
|
for (auto &m_arr : my_pair.second) {
|
|
m_arr.push_back(split_line.at(3));
|
|
m_arr.push_back(split_line.at(2));
|
|
}
|
|
|
|
|
|
}
|
|
} else if ( ( (crush_all == 1) && (match1!="TNAME") && (match1.size() > 0 && match1.at(0) != '#') ) || (find(testnames.begin(), testnames.end(), match1) != testnames.end()) ) {
|
|
|
|
stringstream ss(line);
|
|
string word;
|
|
testdetails.clear();
|
|
while (ss >> word) { // Extract word from the stream.
|
|
testdetails.push_back(word);
|
|
}
|
|
testname = testdetails[0];
|
|
|
|
vector<string> sub_buff;
|
|
|
|
for (int ctr = 0; ctr <= max_col; ++ctr) {
|
|
sub_buff.push_back(" ");
|
|
}
|
|
sub_buff[0] = productname;
|
|
sub_buff[1] = programrev;
|
|
sub_buff[2] = operatorlotname;
|
|
sub_buff[3] = lotname;
|
|
|
|
sub_buff[4] = wafer;
|
|
sub_buff[5] = x_coord;
|
|
sub_buff[6] = y_coord;
|
|
sub_buff[7] = testsite;
|
|
sub_buff[8] = temperature;
|
|
|
|
|
|
|
|
for (int i = 0; i <= (int)(testheader.size()-1); ++i) {
|
|
int index;
|
|
index = testcollookup[testheader[i]];
|
|
|
|
if (testheader[i] == "RESULTS") {
|
|
if (testdetails[i] == "PASS") {
|
|
sub_buff[index] = "1";
|
|
} else {
|
|
sub_buff[index] = "0";
|
|
}
|
|
} else {
|
|
sub_buff[index] = testdetails[i];
|
|
}
|
|
}
|
|
|
|
if (!debug_mode) {
|
|
hash_buff[testname].push_back(sub_buff);
|
|
}
|
|
|
|
|
|
} else if (match1 == "#END_DEVICE") {
|
|
if (!debug_mode) {
|
|
for ( auto &my_pair : hash_buff ) {
|
|
|
|
string test = my_pair.first;
|
|
string fileout = test + ".csv";
|
|
|
|
if (append ==1) {
|
|
|
|
ifstream infile(fileout);
|
|
if (infile.good())
|
|
{
|
|
string sLine;
|
|
|
|
getline(infile, sLine);
|
|
|
|
vector<string> sub_split_string = tokenize(sLine, ",");
|
|
if (sub_split_string.at(0) == "productname") {
|
|
has_header[test] = 1;
|
|
}
|
|
}
|
|
infile.close();
|
|
}
|
|
|
|
|
|
if (!has_header[test]) {
|
|
if (!FILE_HANDLE[test] .is_open()) {
|
|
if (append == 1) {
|
|
FILE_HANDLE[test].open(test + ".csv", ios::app);
|
|
} else {
|
|
FILE_HANDLE[test].open(test + ".csv", ios::out | ios::trunc);
|
|
}
|
|
}
|
|
|
|
FILE_HANDLE[test] << "productname,programrev,operatorlotname,lotname,wafer,x,y,testsite,temperature,testname,vcc,vccio,vccaux,testdoublevalue,testintvalue,testpass,pattern,state,intval,condition1,condition2,condition3,text,bin,binname\n";
|
|
has_header[test] = 1;
|
|
|
|
|
|
}
|
|
|
|
for (auto &m_arr : hash_buff[test]) {
|
|
if (!FILE_HANDLE[test] .is_open()) {
|
|
FILE_HANDLE[test].open(test + ".csv", ios::app);
|
|
}
|
|
FILE_HANDLE[test] << join(m_arr,",") + "\n";
|
|
}
|
|
|
|
hash_buff[test].clear();
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
++line_pos;
|
|
}
|
|
auto time_end = steady_clock::now();
|
|
|
|
cout << "\033[1;32mFinished: \033[0m" << duration_cast<milliseconds>(time_end - time_start).count() << " ms\n";
|
|
|
|
for ( const auto &my_pair : hash_buff ) {
|
|
string test = my_pair.first;
|
|
// string fileout = test + ".csv";
|
|
|
|
// if (hash_buff[test].size() > 0) {
|
|
// FILE_HANDLE[test] << hash_buff[test];
|
|
// hash_buff[test].clear();
|
|
// }
|
|
|
|
FILE_HANDLE[test].close();
|
|
}
|
|
|
|
return 0;
|
|
} |