diff --git a/krash_main.cpp b/krash_main.cpp index 73f4552..3248e82 100644 --- a/krash_main.cpp +++ b/krash_main.cpp @@ -10,12 +10,35 @@ #include #include #include +#include +#include +#include +#include using namespace std; using namespace std::chrono; +std::mutex cout_mutex; + const int BUFFER_SIZE = 2048; +// Helper function for Windows console cursor positioning +inline void set_cursor_position(int row, int col) { + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + COORD pos; + pos.X = col - 1; // 0-based + pos.Y = row - 1; // 0-based + SetConsoleCursorPosition(hConsole, pos); +} + +int get_console_width() { + CONSOLE_SCREEN_BUFFER_INFO csbi; + int columns = 80; // default + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { + columns = csbi.srWindow.Right - csbi.srWindow.Left + 1; + } + return columns; +} inline string join(vector const &strings, string delim) { @@ -47,6 +70,8 @@ inline vector tokenize(string s, string delimiter = " ") } int main(int argc, char** argv) { + system("cls"); + ios::sync_with_stdio(false); cin.tie(NULL); @@ -58,11 +83,12 @@ int main(int argc, char** argv) { int append = 1; int crush_all = 0; int debug_mode = 0; + int allfiles = 0; vector testnames; int c; bool no_opt = true; - while ((c = getopt(argc, argv, "hf:rdt:x")) != -1) { + while ((c = getopt(argc, argv, "hf:ardt:x")) != -1) { switch (c) { case 'h': cout << "Usage: " << argv[0] << " -f [-r ] [-t ] [-h]\n"; @@ -76,6 +102,9 @@ int main(int argc, char** argv) { testnames.push_back(argv[optind] ); } break; + case 'a': + allfiles = 1; + break; case 'r': append = 0; break; @@ -101,310 +130,367 @@ int main(int argc, char** argv) { 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-a => Process all .datalog files in current dir, overrides files specified in -f\n"; cout << "\t\t-x => Exract all tests, overrides tests specified in -t\n\n"; return 1; } - if (filename == "") { - return 0; - } - unordered_map has_header; - unordered_map FILE_HANDLE; - unordered_map< - string, - vector> - > hash_buff; + vector datalog_files; - 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); + if (allfiles == 1 && filename == "") { + namespace fs = std::filesystem; + for (const auto& entry : fs::directory_iterator(fs::current_path())) { + if (entry.is_regular_file() && entry.path().extension() == ".datalog") { + datalog_files.push_back(entry.path().string()); + } } - } - - ifstream file_input; - - file_input = ifstream(filename); - stringstream buffer; - buffer << file_input.rdbuf(); - vector 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 - 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::min(); - for (const auto& value : testcollookup) { - if (value.second > max_col) { - max_col = value.second; + if (datalog_files.empty()) { + cerr << "No .datalog files found in current directory!\n"; + return 1; } + } else { + if (filename == "") { + cerr << "No .datalog file specified!\n"; + return 1; + } + datalog_files.push_back(filename); } - - - vector testheader; - vector testdetails; - - string last_match; - string line; - - + // You can now loop over datalog_files for processing + vector> futures; + int file_num = 1; 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 part_split_line; - string part_line = m_vec_file[part_size]; + for (const auto& filename : datalog_files) { + int my_line = ++file_num; - part_split_line = tokenize(part_line); - if (part_split_line[0] == "#START_DEVICE") { - break; - } + futures.push_back(std::async(std::launch::async, [&, filename, my_line]() { + + if (filename == "") { + return ; + } - } - // 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 split_line; - string match1 = "99"; - string match2 = "99"; + unordered_map has_header; + unordered_map FILE_HANDLE; + unordered_map< + string, + vector> + > hash_buff; - 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); + for(auto& name : testnames) { + has_header[name] = 0; + hash_buff[name].clear(); + if (append == 1) { + FILE_HANDLE[name].open(name + ".csv", ios::app); } else { - lotname = lotname_temp; + FILE_HANDLE[name].open(name + ".csv", ios::out | ios::trunc); } - last_match = "LOT"; } - } else if (match1 == "#WAFER") { - wafer = match2; - last_match = "WAFER"; - } else if (match1 == "#LOTWAFER") { - vector 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); - } - + ifstream file_input; + + file_input = ifstream(filename); + stringstream buffer; + buffer << file_input.rdbuf(); + vector m_vec_file; + m_vec_file = tokenize(buffer.str(), "\n"); - 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)); + + if (!file_input) { + cerr << "Could not open input file!\n"; + return ; + } + + + 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 + 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::min(); + for (const auto& value : testcollookup) { + if (value.second > max_col) { + max_col = value.second; + } + } + + + vector testheader; + vector testdetails; + + string last_match; + string line; + + + + 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 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) % 100 == 0) || (line_pos == max_line_pos)) { + std::lock_guard lock(cout_mutex); // Lock before updating console + + int width = get_console_width(); + std::ostringstream oss; + oss << " File: " << m_filename << " "; + std::string left = oss.str(); + + std::ostringstream progress_oss; + progress_oss << "[" << std::fixed << std::setprecision(3) + << (100 * (float)line_pos / (float)max_line_pos) << "%]"; + std::string right = progress_oss.str(); + + int padding = width - (int)left.length() - (int)right.length(); + if (padding < 0) padding = 0; + + set_cursor_position(my_line, 1); + std::cout << left << std::string(padding, ' ') << right << std::flush; + } + vector split_line; + string match1 = "99"; + string match2 = "99"; + + // istringstream iss(line); + // string word; + // while (iss >> word) split_line.push_back(word); + split_line = tokenize(line); + + + if (split_line.size()>0) { + match1 = split_line.at(0); + + if (split_line.size()>1) { + match2 = split_line.at(1); } - - - } - } 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 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) { + 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 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") { - ifstream infile(fileout); - if (infile.good()) - { - string sLine; - - getline(infile, sLine); - - vector sub_split_string = tokenize(sLine, ","); - if (sub_split_string.at(0) == "productname") { - has_header[test] = 1; + 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)); } - } - infile.close(); + + } + } else if ( ( (crush_all == 1) && (match1!="TNAME") && (match1.size() > 0 && match1.at(0) != '#') ) || (find(testnames.begin(), testnames.end(), match1) != testnames.end()) ) { - - 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(); - + stringstream ss(line); + string word; + testdetails.clear(); + while (ss >> word) { // Extract word from the stream. + testdetails.push_back(word); } + testname = testdetails[0]; + + vector 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 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].seekp(0, ios::end); + if (FILE_HANDLE[test].tellp() == 0) { + 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"; + } + } + + 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; } - } + + + for ( const auto &my_pair : hash_buff ) { + string test = my_pair.first; + // string fileout = test + ".csv"; - ++line_pos; - } - auto time_end = steady_clock::now(); + // if (hash_buff[test].size() > 0) { + // FILE_HANDLE[test] << hash_buff[test]; + // hash_buff[test].clear(); + // } - cout << "\033[1;32mFinished: \033[0m" << duration_cast(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(); + FILE_HANDLE[test].close(); + } + })); } + + + for (auto& fut : futures) fut.get(); + auto time_end = steady_clock::now(); + cout << "\n\n\033[1;32m Finished: \033[0m" << duration_cast(time_end - time_start).count() << " ms\n"; + return 0; } \ No newline at end of file diff --git a/output/krash_main.exe b/output/krash_main.exe deleted file mode 100644 index 2e7f636..0000000 Binary files a/output/krash_main.exe and /dev/null differ diff --git a/release/krash.exe b/release/krash.exe index 0642f5d..7a19a3f 100644 Binary files a/release/krash.exe and b/release/krash.exe differ