Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions libCacheSim/bin/traceAnalyzer/cli_parser.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#include <argp.h>
#include <stdbool.h>
#include <string.h>
Expand Down Expand Up @@ -74,11 +74,13 @@
"enable popularity analysis, output freq:cnt in dataname.popularity file, "
"and prints the skewness to stdout and stat file",
3},
{"popularityDacay", OPTION_ENABLE_POPULARITY_DECAY, NULL,
{"popularityDecay", OPTION_ENABLE_POPULARITY_DECAY, NULL,
OPTION_ARG_OPTIONAL,
"enable popularity decay analysis, this calculates popularity fade as a "
"heatmap. It is an expensive analysis, enable only when needed.",
3},
{"popularityDacay", OPTION_ENABLE_POPULARITY_DECAY, NULL,
OPTION_ARG_OPTIONAL | OPTION_HIDDEN, NULL, 3},
{"reuse", OPTION_ENABLE_REUSE, NULL, OPTION_ARG_OPTIONAL,
"reuse analysis, output a reuse distribution (both real time and virtual "
"time) in dataname.reuse file",
Expand Down Expand Up @@ -110,8 +112,8 @@

{NULL, 0, NULL, 0, "common parameters:", 0},

{"output", OPTION_OUTPUT_PATH, "", OPTION_ARG_OPTIONAL, "Output path", 8},
{"verbose", OPTION_VERBOSE, NULL, OPTION_ARG_OPTIONAL,
{"output", OPTION_OUTPUT_PATH, "PATH", 0, "Output path prefix", 8},
{"verbose", OPTION_VERBOSE, NULL, 0,
"Produce verbose output", 8},
{NULL, 0, NULL, 0, NULL, 0}};

Expand All @@ -128,6 +130,10 @@
arguments->trace_type_params = arg;
break;
case OPTION_OUTPUT_PATH:
if (arg == nullptr) {
argp_usage(state);
exit(1);
}
strncpy(arguments->ofilepath, arg, OFILEPATH_LEN - 1);
arguments->ofilepath[OFILEPATH_LEN - 1] = '\0';
break;
Expand All @@ -149,6 +155,9 @@
case OPTION_TRACK_N_HIT:
arguments->analysis_param.track_n_hit = atoi(arg);
break;
case OPTION_TRACK_N_POPULAR:
arguments->analysis_param.track_n_popular = atoi(arg);
break;
case OPTION_ENABLE_ALL:
arguments->analysis_option.req_rate = true;
arguments->analysis_option.access_pattern = true;
Expand Down Expand Up @@ -187,7 +196,7 @@
break;

case OPTION_VERBOSE:
arguments->verbose = is_true(arg) ? true : false;
arguments->verbose = true;
break;
case ARGP_KEY_ARG:
if (state->arg_num >= N_ARGS) {
Expand Down Expand Up @@ -236,7 +245,6 @@

args->trace_path = NULL;
args->trace_type_params = NULL;
args->verbose = true;
memset(args->ofilepath, 0, OFILEPATH_LEN);
args->n_req = -1;
args->verbose = false;
Expand Down
2 changes: 1 addition & 1 deletion libCacheSim/bin/traceAnalyzer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) {
args.reader, args.ofilepath, args.analysis_option, args.analysis_param);
stat->run();

ofstream ofs("traceStat", ios::out | ios::app);
ofstream ofs(args.ofilepath + string(".traceStat"), ios::out | ios::app);
ofs << *stat << endl;
ofs.close();
cout << *stat;
Expand Down
152 changes: 94 additions & 58 deletions libCacheSim/traceAnalyzer/analyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,76 @@ void traceAnalyzer::TraceAnalyzer::cleanup() {
void traceAnalyzer::TraceAnalyzer::run() {
if (has_run_) return;

auto dump_outputs = [&]() {
ofstream ofs(output_path_ + ".stat", ios::out | ios::app);
ofs << gen_stat_str() << endl;
ofs.close();
Comment on lines +93 to +95
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The main function already writes the summary statistics (from gen_stat_str()) to a .traceStat file and to standard output. This code block duplicates that by writing the same information to a .stat file. To avoid redundancy and keep output handling centralized in main, consider removing these lines. The dump_outputs function would then be responsible only for dumping the detailed statistics from the individual analyzer components (like ttl_stat_, req_rate_stat_, etc.).

Comment on lines +94 to +95
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the stats output filename from a fixed stat to output_path_ + '.stat' is a user-visible behavior change. Existing docs and any workflows that look for stat in the working directory will no longer find it. Either update the documentation/plotting entrypoints accordingly in the same PR, or consider emitting the legacy filename as well for backward compatibility.

Suggested change
ofs << gen_stat_str() << endl;
ofs.close();
ofstream legacy_ofs("stat", ios::out | ios::app);
auto stat_str = gen_stat_str();
ofs << stat_str << endl;
legacy_ofs << stat_str << endl;
ofs.close();
legacy_ofs.close();

Copilot uses AI. Check for mistakes.

if (ttl_stat_ != nullptr) {
ttl_stat_->dump(output_path_);
}

if (req_rate_stat_ != nullptr) {
req_rate_stat_->dump(output_path_);
}

if (reuse_stat_ != nullptr) {
reuse_stat_->dump(output_path_);
}

if (size_stat_ != nullptr) {
size_stat_->dump(output_path_);
}

if (access_stat_ != nullptr) {
access_stat_->dump(output_path_);
}

if (popularity_stat_ != nullptr) {
popularity_stat_->dump(output_path_);
}

if (popularity_decay_stat_ != nullptr) {
popularity_decay_stat_->dump(output_path_);
}

if (prob_at_age_ != nullptr) {
prob_at_age_->dump(output_path_);
}

if (lifetime_stat_ != nullptr) {
lifetime_stat_->dump(output_path_);
}

if (create_future_reuse_ != nullptr) {
create_future_reuse_->dump(output_path_);
}

// if (write_reuse_stat_ != nullptr) {
// write_reuse_stat_->dump(output_path_);
// }

// if (write_future_reuse_stat_ != nullptr) {
// write_future_reuse_stat_->dump(output_path_);
// }

if (scan_detector_ != nullptr) {
scan_detector_->dump(output_path_);
}

has_run_ = true;
};

request_t *req = new_request();
read_one_req(reader_, req);
if (!req->valid) {
start_ts_ = 0;
end_ts_ = 0;
post_processing();
free_request(req);
dump_outputs();
return;
}
start_ts_ = req->clock_time;
int32_t curr_time_window_idx = 0;
int next_time_window_ts = time_window_;
Expand Down Expand Up @@ -226,67 +294,35 @@ void traceAnalyzer::TraceAnalyzer::run() {

free_request(req);

ofstream ofs("stat", ios::out | ios::app);
ofs << gen_stat_str() << endl;
ofs.close();

if (ttl_stat_ != nullptr) {
ttl_stat_->dump(output_path_);
}

if (req_rate_stat_ != nullptr) {
req_rate_stat_->dump(output_path_);
}

if (reuse_stat_ != nullptr) {
reuse_stat_->dump(output_path_);
}

if (size_stat_ != nullptr) {
size_stat_->dump(output_path_);
}

if (access_stat_ != nullptr) {
access_stat_->dump(output_path_);
}

if (popularity_stat_ != nullptr) {
popularity_stat_->dump(output_path_);
}

if (popularity_decay_stat_ != nullptr) {
popularity_decay_stat_->dump(output_path_);
}

if (prob_at_age_ != nullptr) {
prob_at_age_->dump(output_path_);
}

if (lifetime_stat_ != nullptr) {
lifetime_stat_->dump(output_path_);
}

if (create_future_reuse_ != nullptr) {
create_future_reuse_->dump(output_path_);
}

// if (write_reuse_stat_ != nullptr) {
// write_reuse_stat_->dump(output_path_);
// }

// if (write_future_reuse_stat_ != nullptr) {
// write_future_reuse_stat_->dump(output_path_);
// }

if (scan_detector_ != nullptr) {
scan_detector_->dump(output_path_);
}

has_run_ = true;
dump_outputs();
}

string traceAnalyzer::TraceAnalyzer::gen_stat_str() {
stat_ss_.clear();
if (n_req_ == 0) {
stat_ss_ << setprecision(4) << fixed << "dat: " << reader_->trace_path
<< "\n"
<< "number of requests: 0, number of objects: 0\n"
<< "number of req GiB: 0.0000, number of obj GiB: 0.0000\n"
<< "compulsory miss ratio (req/byte): 0.0000/0.0000\n"
<< "object size weighted by req/obj: 0/0\n"
<< "frequency mean: 0.0000\n"
<< "time span: 0(0.0000 day)\n"
<< "write: 0(0.0000), overwrite: 0(0.0000), del:0(0.0000)\n"
<< "X-hit (number of obj accessed X times): ";
for (int i = 0; i < track_n_hit_; i++) {
stat_ss_ << "0(0.0000), ";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This line adds a trailing comma and space to the output string (e.g., 0(0.0000), 0(0.0000), ). To produce cleaner output, it's better to avoid adding the separator after the last element. A similar issue exists in the loop for track_n_popular_ below, and also in the loops that handle the case when n_req_ > 0.

      stat_ss_ << "0(0.0000)" << (i < track_n_hit_ - 1 ? ", " : "");

}
stat_ss_ << "\n";

stat_ss_ << "freq (fraction) of the most popular obj: ";
for (int i = 0; i < track_n_popular_; i++) {
stat_ss_ << "0(0.0000), ";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the loop for track_n_hit_, this line adds a trailing comma and space. It's better to avoid this for cleaner output.

      stat_ss_ << "0(0.0000)" << (i < track_n_popular_ - 1 ? ", " : "");

}
stat_ss_ << "\n";
return stat_ss_.str();
}

double cold_miss_ratio = (double)obj_map_.size() / (double)n_req_;
double byte_cold_miss_ratio =
(double)sum_obj_size_obj / (double)sum_obj_size_req;
Expand Down Expand Up @@ -354,7 +390,7 @@ void traceAnalyzer::TraceAnalyzer::post_processing() {
}
}

if (option_.popularity) {
if (option_.popularity && !obj_map_.empty()) {
popularity_stat_ = new Popularity(obj_map_);
auto &sorted_freq = popularity_stat_->get_sorted_freq();
int n = std::min(track_n_popular_, (int)sorted_freq.size());
Expand Down
3 changes: 2 additions & 1 deletion libCacheSim/traceReader/reader.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
//
// reader.c
// libCacheSim
Expand Down Expand Up @@ -241,7 +241,8 @@
return 1;
}

if (reader->cap_at_n_req > 1 && reader->n_read_req >= reader->cap_at_n_req) {
if (reader->cap_at_n_req >= 0 &&
reader->n_read_req >= reader->cap_at_n_req) {
DEBUG("read_one_req: processed %ld requests capped by the user\n",
(long)reader->n_read_req);
req->valid = false;
Expand Down
35 changes: 25 additions & 10 deletions scripts/run_traceAnalyzer.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/bin/bash

set -euo pipefail

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Don't abort the helper script on missing popularity output

On traces with fewer than 200 distinct objects, Popularity::dump() returns without creating *.popularity (libCacheSim/traceAnalyzer/popularity.cpp:18-23,55-60), and scripts/traceAnalysis/popularity.py immediately open()s that file. Turning on set -e here makes scripts/run_traceAnalyzer.sh exit non-zero for those valid small traces (or capped runs), even though the analyzer has already produced the other outputs; before this change the plotting phase was effectively best-effort.

Useful? React with 👍 / 👎.


function help() {
echo "Usage: $0 <tracepath> <trace_format> [<trace_format_parameters>]"
}
Expand All @@ -9,20 +11,33 @@ if [ $# -lt 2 ]; then
exit 1;
fi

CURR_DIR=$(cd $(dirname $0); pwd)
CURR_DIR=$(cd "$(dirname "$0")"; pwd)
REPO_DIR=$(cd "${CURR_DIR}/.."; pwd)
TRACE_ANALYZER="${REPO_DIR}/_build/bin/traceAnalyzer"

if [ ! -x "${TRACE_ANALYZER}" ]; then
echo "traceAnalyzer binary not found at ${TRACE_ANALYZER}; build the project first" >&2
exit 1
fi

tracepath=$1
trace_format=$2
trace_format_parameters=${@:3}
shift 2

analyzer_args=("${tracepath}" "${trace_format}" "--common")
if [ $# -gt 0 ]; then
analyzer_args+=("--trace-type-params" "$*")
Comment on lines +27 to +29

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Forward analyzer flags instead of folding them into trace params

This now rewrites every argument after <trace_format> into a single --trace-type-params string. As a result, previously valid invocations like scripts/run_traceAnalyzer.sh ... --num-req 100000, --output out/prefix, or --popularityDecay no longer reach traceAnalyzer; they are handed to parse_reader_params(), which exits on unknown keys (libCacheSim/bin/cli_reader_utils.c:183-185). That breaks capped analyses and custom output prefixes through the helper script.

Useful? React with 👍 / 👎.

fi

Comment on lines +29 to 31
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script now treats all extra arguments as a single value for --trace-type-params (analyzer_args+=('--trace-type-params' "$*")). This prevents callers from passing any other traceAnalyzer flags (e.g., --output, --time-window, --popularityDecay, etc.), and also breaks if the user already supplies -t/--trace-type-params in the extra args (it would become part of the params string). Consider forwarding remaining args verbatim (e.g., append "$@") and only adding --trace-type-params when you explicitly want to support a third positional parameter, or provide a dedicated flag in the script for trace-type params.

Suggested change
analyzer_args+=("--trace-type-params" "$*")
fi
# Treat the third positional argument as trace-type parameters
analyzer_args+=("--trace-type-params" "$1")
shift 1
fi
# Forward any remaining arguments verbatim to traceAnalyzer
if [ $# -gt 0 ]; then
analyzer_args+=("$@")
fi

Copilot uses AI. Check for mistakes.
./_build/bin/traceAnalyzer ${tracepath} ${trace_format} ${trace_format_parameters} --common
"${TRACE_ANALYZER}" "${analyzer_args[@]}"

dataname=$(basename ${tracepath})
python3 ${CURR_DIR}/traceAnalysis/access_pattern.py ${dataname}.accessRtime
python3 ${CURR_DIR}/traceAnalysis/access_pattern.py ${dataname}.accessVtime
python3 ${CURR_DIR}/traceAnalysis/req_rate.py ${dataname}.reqRate_w300
python3 ${CURR_DIR}/traceAnalysis/size.py ${dataname}.size
python3 ${CURR_DIR}/traceAnalysis/reuse.py ${dataname}.reuse
python3 ${CURR_DIR}/traceAnalysis/popularity.py ${dataname}.popularity
dataname=$(basename "${tracepath}")
python3 "${CURR_DIR}/traceAnalysis/access_pattern.py" "${dataname}.accessRtime"
python3 "${CURR_DIR}/traceAnalysis/access_pattern.py" "${dataname}.accessVtime"
python3 "${CURR_DIR}/traceAnalysis/req_rate.py" "${dataname}.reqRate_w300"
python3 "${CURR_DIR}/traceAnalysis/size.py" "${dataname}.size"
python3 "${CURR_DIR}/traceAnalysis/reuse.py" "${dataname}.reuse"
python3 "${CURR_DIR}/traceAnalysis/popularity.py" "${dataname}.popularity"
# python3 ${CURR_DIR}/traceAnalysis/requestAge.py ${dataname}.requestAge
# python3 ${CURR_DIR}/traceAnalysis/size_heatmap.py ${dataname}.sizeWindow_w300
# python3 ${CURR_DIR}/traceAnalysis/futureReuse.py ${dataname}.access
Expand Down
Loading