Skip to content

Commit 1dee0f1

Browse files
mechanism for profiling Z3 solver API calls
1 parent dd35157 commit 1dee0f1

File tree

2 files changed

+77
-7
lines changed

2 files changed

+77
-7
lines changed

headers/wasm/config.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ const bool PROFILE_TIME = true;
1919
const bool PROFILE_TIME = false;
2020
#endif
2121

22+
#ifdef ENABLE_PROFILE_Z3_API_CALL
23+
const bool PROFILE_Z3_API_CALL = true;
24+
#else
25+
const bool PROFILE_Z3_API_CALL = false;
26+
#endif
27+
2228
#ifdef ENABLE_PROFILE_CACHE
2329
const bool PROFILE_CACHE = true;
2430
#else

headers/wasm/profile.hpp

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
#include "config.hpp"
55
#include "utils.hpp"
6+
#include "z3++.h"
67
#include <array>
78
#include <chrono>
9+
#include <filesystem>
10+
#include <fstream>
811
#include <iomanip>
912
#include <ratio>
1013
#include <string>
@@ -50,7 +53,33 @@ enum class TimeProfileKind {
5053

5154
class Profile_t {
5255
public:
53-
Profile_t() : step_count(0), cache_hit_count(0), cache_miss_count(0) {}
56+
Profile_t() : step_count(0), cache_hit_count(0), cache_miss_count(0) {
57+
// refresh the output profile directory
58+
if (PROFILE_Z3_API_CALL) {
59+
std::filesystem::path out_path(base_profile_output_path);
60+
std::error_code ec;
61+
std::filesystem::remove_all(out_path, ec);
62+
if (ec) {
63+
throw std::runtime_error("Failed to clear output directory: " +
64+
ec.message());
65+
}
66+
std::filesystem::create_directories(out_path, ec);
67+
if (ec) {
68+
throw std::runtime_error("Failed to create output directory: " +
69+
ec.message());
70+
}
71+
std::string record_file =
72+
base_profile_output_path + "/z3_solver_time_record.csv";
73+
std::ofstream ofs(record_file);
74+
ofs << "Expression file,time spent (s),is_sat\n";
75+
ofs.close();
76+
std::filesystem::create_directories(z3_expr_output_path, ec);
77+
if (ec) {
78+
throw std::runtime_error("Failed to create z3 expr output directory: " +
79+
ec.message());
80+
}
81+
}
82+
}
5483

5584
void cache_hit() {
5685
if (PROFILE_CACHE)
@@ -131,11 +160,13 @@ class Profile_t {
131160
<< std::setprecision(15)
132161
<< time_count[static_cast<std::size_t>(TimeProfileKind::INSTR)]
133162
<< std::endl;
134-
std::cout << "Total time in solver (s): " << std::setprecision(15)
135-
<< time_count[static_cast<std::size_t>(TimeProfileKind::SOLVER_TOTAL)]
136-
<< std::endl;
163+
std::cout
164+
<< "Total time in solver (s): " << std::setprecision(15)
165+
<< time_count[static_cast<std::size_t>(TimeProfileKind::SOLVER_TOTAL)]
166+
<< std::endl;
137167
std::cout << "Total time in z3 api call (s): " << std::setprecision(15)
138-
<< time_count[static_cast<std::size_t>(TimeProfileKind::CALL_Z3_SOLVER)]
168+
<< time_count[static_cast<std::size_t>(
169+
TimeProfileKind::CALL_Z3_SOLVER)]
139170
<< std::endl;
140171
std::cout << "Total time in resuming from snapshot (s): "
141172
<< std::setprecision(15)
@@ -227,7 +258,8 @@ class Profile_t {
227258
<< time_count[static_cast<std::size_t>(TimeProfileKind::INSTR)]
228259
<< ",\n";
229260
os << " \"total_time_solver_s\": " << std::setprecision(15)
230-
<< time_count[static_cast<std::size_t>(TimeProfileKind::CALL_Z3_SOLVER)]
261+
<< time_count[static_cast<std::size_t>(
262+
TimeProfileKind::CALL_Z3_SOLVER)]
231263
<< ",\n";
232264
os << " \"total_time_resuming_from_snapshot_s\": "
233265
<< std::setprecision(15)
@@ -256,6 +288,30 @@ class Profile_t {
256288
os << " }\n";
257289
}
258290

291+
void record_z3_solver_time(z3::expr expr, double time, bool is_sat) {
292+
// Write z3 expression in a file, and write the time spent in solving it and
293+
// the file path in another file
294+
if (PROFILE_Z3_API_CALL) {
295+
static int count = 0;
296+
std::string expr_file =
297+
z3_expr_output_path + "/z3_expr_" + std::to_string(count) + ".smt2";
298+
std::error_code ec;
299+
std::ofstream ofs(expr_file);
300+
ofs << expr;
301+
ofs.close();
302+
std::string record_file =
303+
base_profile_output_path + "/z3_solver_time_record.csv";
304+
std::ofstream rofs(record_file, std::ios::app);
305+
rofs << expr_file << "," << std::setprecision(15) << time << ","
306+
<< (is_sat ? "sat" : "unsat") << "\n";
307+
rofs.close();
308+
count++;
309+
}
310+
}
311+
312+
std::string base_profile_output_path = "genwasym_profile_output";
313+
std::string z3_expr_output_path = "genwasym_profile_output/z3_expressions";
314+
259315
// record the time spent in main instruction execution, in seconds
260316
void add_instruction_time(TimeProfileKind kind, double time) {
261317
time_count[static_cast<std::size_t>(kind)] += time;
@@ -283,18 +339,26 @@ static Profile_t Profile;
283339
class ManagedTimer {
284340
public:
285341
ManagedTimer() = delete;
286-
ManagedTimer(TimeProfileKind kind) : kind(kind) {
342+
ManagedTimer(TimeProfileKind kind) : kind(kind), time_ref(nullptr) {
343+
start = std::chrono::high_resolution_clock::now();
344+
}
345+
ManagedTimer(TimeProfileKind kind, double &time_ref)
346+
: kind(kind), time_ref(&time_ref) {
287347
start = std::chrono::high_resolution_clock::now();
288348
}
289349
~ManagedTimer() {
290350
auto end = std::chrono::high_resolution_clock::now();
291351
std::chrono::duration<double> elapsed = end - start;
292352
Profile.add_instruction_time(kind, elapsed.count());
353+
if (time_ref != nullptr) {
354+
*time_ref += elapsed.count();
355+
}
293356
}
294357

295358
private:
296359
TimeProfileKind kind;
297360
std::chrono::high_resolution_clock::time_point start;
361+
double *time_ref;
298362
};
299363

300364
using Time = std::chrono::time_point<std::chrono::steady_clock>;

0 commit comments

Comments
 (0)