mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			287 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*++
 | 
						|
Copyright (c) 2017 Microsoft Corporation
 | 
						|
 | 
						|
Module Name:
 | 
						|
 | 
						|
    main.cpp
 | 
						|
 | 
						|
Abstract:
 | 
						|
 | 
						|
    Main file for qprofdiff.
 | 
						|
 | 
						|
Author:
 | 
						|
 | 
						|
    Christoph M. Wintersteiger (cwinter)
 | 
						|
 | 
						|
Revision History:
 | 
						|
--*/
 | 
						|
#include<errno.h>
 | 
						|
#include<limits.h>
 | 
						|
 | 
						|
#include<string>
 | 
						|
#include<iostream>
 | 
						|
#include<fstream>
 | 
						|
#include<map>
 | 
						|
#include<vector>
 | 
						|
#include<set>
 | 
						|
#include<algorithm>
 | 
						|
 | 
						|
using namespace std;
 | 
						|
 | 
						|
set<string> options;
 | 
						|
 | 
						|
// Profile format:
 | 
						|
// [quantifier_instances] qname : num_instances : max_generation : max_cost_s
 | 
						|
const string prefix = "[quantifier_instances]";
 | 
						|
unsigned prefix_len = prefix.length();
 | 
						|
typedef struct { unsigned num_instances, max_generation, max_cost; } map_entry;
 | 
						|
 | 
						|
string trim(string str) {
 | 
						|
    size_t linx = str.find_first_not_of(' ');
 | 
						|
    size_t rinx = str.find_last_not_of(' ');
 | 
						|
    return str.substr(linx, rinx-linx+1);
 | 
						|
}
 | 
						|
 | 
						|
int parse(string const & filename, map<string, map_entry> & data) {
 | 
						|
    ifstream fs(filename.c_str());
 | 
						|
 | 
						|
    if (!fs.is_open()) {
 | 
						|
        cout << "Can't open file '" << filename << "'" << endl;
 | 
						|
        return ENOENT;
 | 
						|
    }
 | 
						|
 | 
						|
    string qid;
 | 
						|
    string tokens[4];
 | 
						|
    unsigned cur_token = 0;
 | 
						|
 | 
						|
    while (!fs.eof()) {
 | 
						|
        string line;
 | 
						|
        getline(fs, line);
 | 
						|
 | 
						|
        if (line.substr(0, prefix_len) == prefix) {
 | 
						|
            line = trim(line.substr(prefix_len));
 | 
						|
            size_t from = 0, ti = 0;
 | 
						|
            for (size_t inx = line.find(" : ", from);
 | 
						|
                inx != string::npos;
 | 
						|
                inx = line.find(" : ", from)) {
 | 
						|
                tokens[ti] = trim(line.substr(from, inx-from));
 | 
						|
                from = inx+1;
 | 
						|
                ti++;
 | 
						|
            }
 | 
						|
            if (from != line.length() && ti < 4)
 | 
						|
                tokens[ti] = trim(line.substr(from));
 | 
						|
 | 
						|
            qid = tokens[0];
 | 
						|
 | 
						|
            if (data.find(qid) == data.end()) {
 | 
						|
                map_entry & entry = data[qid];
 | 
						|
                entry.num_instances = entry.max_generation = entry.max_cost = 0;
 | 
						|
            }
 | 
						|
 | 
						|
            // Existing entries represent previous occurrences of quantifiers
 | 
						|
            // that, at some point, were removed (e.g. backtracked). We sum
 | 
						|
            // up instances from all occurrences of the same qid.
 | 
						|
            map_entry & entry = data[qid];
 | 
						|
            entry.num_instances += atoi(tokens[1].c_str());
 | 
						|
            entry.max_generation = max(entry.max_generation, (unsigned)atoi(tokens[2].c_str()));
 | 
						|
            entry.max_cost = max(entry.max_cost, (unsigned)atoi(tokens[3].c_str()));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    fs.close();
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
void display_data(map<string, map_entry> & data) {
 | 
						|
    for (map<string, map_entry>::iterator it = data.begin();
 | 
						|
         it != data.end();
 | 
						|
         it++)
 | 
						|
        cout << it->first << ": " << it->second.num_instances <<
 | 
						|
                             ", " << it->second.max_generation <<
 | 
						|
                             ", " << it->second.max_cost << endl;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    int d_num_instances, d_max_generation, d_max_cost;
 | 
						|
    bool left_only, right_only;
 | 
						|
} diff_entry;
 | 
						|
 | 
						|
typedef struct { string qid; diff_entry e; } diff_item;
 | 
						|
 | 
						|
#define DIFF_LT(X) bool diff_item_lt_ ## X (diff_item const & l, diff_item const & r) { \
 | 
						|
    int l_lt_r = l.e.d_ ## X < r.e.d_ ## X; \
 | 
						|
    int l_eq_r = l.e.d_ ## X == r.e.d_ ## X; \
 | 
						|
    return \
 | 
						|
        l.e.left_only ? (r.e.left_only ? ((l_eq_r) ? l.qid < r.qid : l_lt_r) : false) : \
 | 
						|
        l.e.right_only ? (r.e.right_only ? ((l_eq_r) ? l.qid < r.qid : l_lt_r) : true) : \
 | 
						|
        r.e.right_only ? false : \
 | 
						|
        r.e.left_only ? true : \
 | 
						|
        l_lt_r; \
 | 
						|
}
 | 
						|
 | 
						|
DIFF_LT(num_instances)
 | 
						|
DIFF_LT(max_generation)
 | 
						|
DIFF_LT(max_cost)
 | 
						|
 | 
						|
int indicate(diff_entry const & e, bool suppress_unchanged) {
 | 
						|
    if (e.left_only) {
 | 
						|
        cout << "< ";
 | 
						|
        return INT_MIN;
 | 
						|
    }
 | 
						|
    else if (e.right_only) {
 | 
						|
        cout << "> ";
 | 
						|
        return INT_MAX;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        int const & delta =
 | 
						|
            (options.find("-si") != options.end()) ? e.d_num_instances :
 | 
						|
            (options.find("-sg") != options.end()) ? e.d_max_generation :
 | 
						|
            (options.find("-sc") != options.end()) ? e.d_max_cost :
 | 
						|
            e.d_num_instances;
 | 
						|
 | 
						|
        if (delta < 0)
 | 
						|
            cout << "+ ";
 | 
						|
        else if (delta > 0)
 | 
						|
            cout << "- ";
 | 
						|
        else if (delta == 0 && !suppress_unchanged)
 | 
						|
            cout << "= ";
 | 
						|
 | 
						|
        return delta;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void diff(map<string, map_entry> & left, map<string, map_entry> & right) {
 | 
						|
    map<string, diff_entry> diff_data;
 | 
						|
 | 
						|
    for (map<string, map_entry>::const_iterator lit = left.begin();
 | 
						|
        lit != left.end();
 | 
						|
        lit++) {
 | 
						|
        string const & qid = lit->first;
 | 
						|
        map_entry const & lentry = lit->second;
 | 
						|
 | 
						|
        map<string, map_entry>::const_iterator rit = right.find(qid);
 | 
						|
        if (rit != right.end()) {
 | 
						|
            map_entry const & rentry = rit->second;
 | 
						|
            diff_entry & de = diff_data[qid];
 | 
						|
 | 
						|
            de.left_only = de.right_only = false;
 | 
						|
            de.d_num_instances = lentry.num_instances - rentry.num_instances;
 | 
						|
            de.d_max_generation = lentry.max_generation - rentry.max_generation;
 | 
						|
            de.d_max_cost = lentry.max_cost - rentry.max_cost;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            diff_entry & de = diff_data[qid];
 | 
						|
            de.left_only = true;
 | 
						|
            de.right_only = false;
 | 
						|
            de.d_num_instances = lentry.num_instances;
 | 
						|
            de.d_max_generation = lentry.max_generation;
 | 
						|
            de.d_max_cost = lentry.max_cost;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for (map<string, map_entry>::const_iterator rit = right.begin();
 | 
						|
        rit != right.end();
 | 
						|
        rit++) {
 | 
						|
        string const & qid = rit->first;
 | 
						|
        map_entry const & rentry = rit->second;
 | 
						|
 | 
						|
        map<string, map_entry>::const_iterator lit = left.find(qid);
 | 
						|
        if (lit == left.end()) {
 | 
						|
            diff_entry & de = diff_data[qid];
 | 
						|
            de.left_only = false;
 | 
						|
            de.right_only = true;
 | 
						|
            de.d_num_instances = -(int)rentry.num_instances;
 | 
						|
            de.d_max_generation = -(int)rentry.max_generation;
 | 
						|
            de.d_max_cost = -(int)rentry.max_cost;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    vector<diff_item> flat_data;
 | 
						|
    for (map<string, diff_entry>::const_iterator it = diff_data.begin();
 | 
						|
        it != diff_data.end();
 | 
						|
        it++) {
 | 
						|
        flat_data.push_back(diff_item());
 | 
						|
        flat_data.back().qid = it->first;
 | 
						|
        flat_data.back().e = it->second;
 | 
						|
    }
 | 
						|
 | 
						|
    stable_sort(flat_data.begin(), flat_data.end(),
 | 
						|
        options.find("-si") != options.end() ? diff_item_lt_num_instances :
 | 
						|
        options.find("-sg") != options.end() ? diff_item_lt_max_generation :
 | 
						|
        options.find("-sc") != options.end() ? diff_item_lt_max_cost :
 | 
						|
        diff_item_lt_num_instances);
 | 
						|
 | 
						|
    bool suppress_unchanged = options.find("-n") != options.end();
 | 
						|
 | 
						|
    for (vector<diff_item>::const_iterator it = flat_data.begin();
 | 
						|
        it != flat_data.end();
 | 
						|
        it++) {
 | 
						|
        diff_item const & d = *it;
 | 
						|
        string const & qid = d.qid;
 | 
						|
        diff_entry const & e = d.e;
 | 
						|
 | 
						|
        int delta = indicate(e, suppress_unchanged);
 | 
						|
 | 
						|
        if (!(delta == 0 && suppress_unchanged))
 | 
						|
            cout << qid << " (" <<
 | 
						|
                (e.d_num_instances > 0 ? "" : "+") << -e.d_num_instances << " inst., " <<
 | 
						|
                (e.d_max_generation > 0 ? "" : "+") << -e.d_max_generation << " max. gen., " <<
 | 
						|
                (e.d_max_cost > 0 ? "" : "+") << -e.d_max_cost << " max. cost)" <<
 | 
						|
                endl;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void display_usage() {
 | 
						|
    cout << "Usage: qprofdiff [options] <filename> <filename>" << endl;
 | 
						|
    cout << "Options:" << endl;
 | 
						|
    cout << " -n      Suppress unchanged items" << endl;
 | 
						|
    cout << " -si     Sort by difference in number of instances" << endl;
 | 
						|
    cout << " -sg     Sort by difference in max. generation" << endl;
 | 
						|
    cout << " -sc     Sort by difference in max. cost" << endl;
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char ** argv) {
 | 
						|
    char * filename1 = 0;
 | 
						|
    char * filename2 = 0;
 | 
						|
 | 
						|
    for (int i = 1; i < argc; i++) {
 | 
						|
        int len = string(argv[i]).length();
 | 
						|
        if (len > 1 && argv[i][0] == '-') {
 | 
						|
            options.insert(string(argv[i]));
 | 
						|
        }
 | 
						|
        else if (filename1 == 0)
 | 
						|
            filename1 = argv[i];
 | 
						|
        else if (filename2 == 0)
 | 
						|
            filename2 = argv[i];
 | 
						|
        else {
 | 
						|
            cout << "Invalid argument: " << argv[i] << endl << endl;
 | 
						|
            display_usage();
 | 
						|
            return EINVAL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (filename1 == 0 || filename2 == 0) {
 | 
						|
        cout << "Two filenames required." << endl << endl;
 | 
						|
        display_usage();
 | 
						|
        return EINVAL;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    cout << "Comparing " << filename1 << " to " << filename2 << endl;
 | 
						|
 | 
						|
    map<string, map_entry> data1, data2;
 | 
						|
 | 
						|
    int r = parse(filename1, data1);
 | 
						|
    if (r != 0) return r;
 | 
						|
    r = parse(filename2, data2);
 | 
						|
    if (r != 0) return r;
 | 
						|
 | 
						|
    // display_data(data1);
 | 
						|
    // display_data(data2);
 | 
						|
 | 
						|
    diff(data1, data2);
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 |