fprintf(ofp, "\n");
}
+struct __q2d {
+ FILE *ofp;
+ void *q2d_all;
+ int n;
+};
+void __output_q2d_histo(struct d_info *dip, void *arg)
+{
+ struct __q2d *q2dp = arg;
+
+ if (q2d_ok(dip->q2d_priv)) {
+ char scratch[15];
+ FILE *ofp = q2dp->ofp;
+
+ fprintf(q2dp->ofp, "%10s | ", make_dev_hdr(scratch, 15, dip));
+ q2d_display(ofp, dip->q2d_priv);
+ q2d_acc(q2dp->q2d_all, dip->q2d_priv);
+ q2dp->n++;
+ }
+}
+
+void output_q2d_histo(FILE *ofp)
+{
+ struct __q2d __q2d = {
+ .ofp = ofp,
+ .q2d_all = q2d_init(),
+ .n = 0
+ };
+
+ fprintf(ofp, "%10s | ", "DEV");
+ q2d_display_header(ofp);
+ fprintf(ofp, "--------- | ");
+ q2d_display_dashes(ofp);
+ dip_foreach_out(__output_q2d_histo, &__q2d);
+
+ if (__q2d.n) {
+ fprintf(ofp, "========== | ");
+ q2d_display_dashes(ofp);
+ fprintf(ofp, "%10s | ", "AVG");
+ q2d_display(ofp, __q2d.q2d_all);
+ fprintf(ofp, "\n");
+ }
+}
+
+int n_merges = 0;
+struct {
+ unsigned long long nq, nd, blkmin, blkmax, total;
+} merge_data;
void __output_dip_merge_ratio(struct d_info *dip, void *arg)
{
double blks_avg;
char scratch[15];
- double ratio, q2c_n = dip->avgs.q2c.n, d2c_n = dip->n_ds;
+ double ratio, q2c_n, d2c_n;
+
+ if (dip->n_qs == 0 || dip->n_ds == 0)
+ return;
+ else if (dip->n_qs < dip->n_ds)
+ dip->n_qs = dip->n_ds;
+ q2c_n = dip->n_qs;
+ d2c_n = dip->n_ds;
if (q2c_n > 0.0 && d2c_n > 0.0) {
- ratio = q2c_n / d2c_n;
+ if (q2c_n < d2c_n)
+ ratio = 1.0;
+ else
+ ratio = q2c_n / d2c_n;
blks_avg = (double)dip->avgs.blks.total / d2c_n;
fprintf((FILE *)arg,
"%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
make_dev_hdr(scratch, 15, dip),
- (unsigned long long)dip->avgs.q2c.n,
+ (unsigned long long)dip->n_qs,
(unsigned long long)dip->n_ds,
ratio,
(unsigned long long)dip->avgs.blks.min,
(unsigned long long)dip->avgs.blks.max,
(unsigned long long)dip->avgs.blks.total);
+ if (n_merges++ == 0) {
+ merge_data.blkmin = dip->avgs.blks.min;
+ merge_data.blkmax = dip->avgs.blks.max;
+ }
+
+ merge_data.nq += dip->n_qs;
+ merge_data.nd += dip->n_ds;
+ merge_data.total += dip->avgs.blks.total;
+ if (dip->avgs.blks.min < merge_data.blkmin)
+ merge_data.blkmin = dip->avgs.blks.min;
+ if (dip->avgs.blks.max > merge_data.blkmax)
+ merge_data.blkmax = dip->avgs.blks.max;
}
}
fprintf(ofp, "%10s | %8s %8s %7s | %8s %8s %8s %8s\n", "DEV", "#Q", "#D", "Ratio", "BLKmin", "BLKavg", "BLKmax", "Total");
fprintf(ofp, "---------- | -------- -------- ------- | -------- -------- -------- --------\n");
dip_foreach_out(__output_dip_merge_ratio, ofp);
+ if (n_merges > 1) {
+ fprintf(ofp, "---------- | -------- -------- ------- | -------- -------- -------- --------\n");
+ fprintf(ofp, "%10s | %8s %8s %7s | %8s %8s %8s %8s\n", "DEV", "#Q", "#D", "Ratio", "BLKmin", "BLKavg", "BLKmax", "Total");
+ fprintf((FILE *)ofp,
+ "%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
+ "TOTAL", merge_data.nq, merge_data.nd,
+ (float)merge_data.nq / (float)merge_data.nd,
+ merge_data.blkmin,
+ merge_data.total / merge_data.nd,
+ merge_data.blkmax, merge_data.total);
+ }
fprintf(ofp, "\n");
}
fprintf(ofp, "\n");
}
-void __output_dip_seek_info(struct d_info *dip, void *arg)
+struct seek_mode_info {
+ struct seek_mode_info *next;
+ long long mode;
+ int nseeks;
+};
+struct o_seek_info {
+ long long nseeks, median;
+ double mean;
+ struct seek_mode_info *head;
+} seek_info;
+int n_seeks;
+
+void output_seek_mode_info(FILE *ofp, struct o_seek_info *sip)
+{
+ struct seek_mode_info *p, *this, *new_list = NULL;
+
+ ASSERT(sip->head != NULL);
+ while ((this = sip->head) != NULL) {
+ sip->head = this->next;
+ this->next = NULL;
+
+ if (new_list == NULL || this->nseeks > new_list->nseeks)
+ new_list = this;
+ else if (this->nseeks == new_list->nseeks) {
+ assert(this->nseeks == new_list->nseeks);
+ for (p = new_list; p != NULL; p = p->next)
+ if (p->mode == this->mode)
+ break;
+
+ if (p)
+ this->nseeks += p->nseeks;
+ else
+ this->next = new_list;
+ new_list = this;
+ }
+ }
+
+ fprintf(ofp, "%10s | %15lld %15.1lf %15lld | %lld(%d)",
+ "Average", sip->nseeks, sip->mean / sip->nseeks,
+ sip->median / sip->nseeks, new_list->mode, new_list->nseeks);
+
+ for (p = new_list->next; p != NULL; p = p->next)
+ fprintf(ofp, " %lld(%d)", p->mode, p->nseeks);
+}
+
+void add_seek_mode_info(struct o_seek_info *sip, struct mode *mp)
+{
+ int i;
+ long long *lp = mp->modes;
+ struct seek_mode_info *smip;
+
+ n_seeks++;
+ for (i = 0; i < mp->nmds; i++, lp++) {
+ for (smip = sip->head; smip; smip = smip->next) {
+ if (smip->mode == *lp) {
+ smip->nseeks += mp->most_seeks;
+ break;
+ }
+ }
+ if (!smip) {
+ struct seek_mode_info *new = malloc(sizeof(*new));
+
+ new->next = sip->head;
+ sip->head = new;
+ new->mode = *lp;
+ new->nseeks = mp->most_seeks;
+
+ add_buf(new);
+ }
+ }
+}
+
+static void do_output_dip_seek_info(struct d_info *dip, FILE *ofp, int is_q2q)
{
double mean;
int i, nmodes;
char dev_info[15];
long long median;
struct mode m;
- FILE *ofp = arg;
+ void *handle = is_q2q ? dip->q2q_handle : dip->seek_handle;
- nseeks = seeki_nseeks(dip->seek_handle);
+ nseeks = seeki_nseeks(handle);
if (nseeks > 0) {
- mean = seeki_mean(dip->seek_handle);
- median = seeki_median(dip->seek_handle);
- nmodes = seeki_mode(dip->seek_handle, &m);
+ mean = seeki_mean(handle);
+ median = seeki_median(handle);
+ nmodes = seeki_mode(handle, &m);
fprintf(ofp, "%10s | %15lld %15.1lf %15lld | %lld(%d)",
make_dev_hdr(dev_info, 15, dip), nseeks, mean, median,
for (i = 1; i < nmodes; i++)
fprintf(ofp, " %lld", m.modes[i]);
fprintf(ofp, "\n");
+
+ seek_info.nseeks += nseeks;
+ seek_info.mean += (nseeks * mean);
+ seek_info.median += (nseeks * median);
+ add_seek_mode_info(&seek_info, &m);
+ free(m.modes);
}
}
+void __output_dip_seek_info(struct d_info *dip, void *arg)
+{
+ do_output_dip_seek_info(dip, (FILE *)arg, 0);
+}
+
+void __output_dip_q2q_seek_info(struct d_info *dip, void *arg)
+{
+ do_output_dip_seek_info(dip, (FILE *)arg, 1);
+}
+
void output_dip_seek_info(FILE *ofp)
{
+ n_seeks = 1;
+ memset(&seek_info, 0, sizeof(seek_info));
+
fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n", "DEV", "NSEEKS",
"MEAN", "MEDIAN", "MODE");
- fprintf(ofp, "---------- "
- "| --------------- --------------- --------------- "
- "| ---------------\n");
+ fprintf(ofp, "---------- | --------------- --------------- --------------- | ---------------\n");
dip_foreach_out(__output_dip_seek_info, ofp);
+ if (n_seeks > 1) {
+ fprintf(ofp, "---------- | --------------- --------------- --------------- | ---------------\n");
+ fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n",
+ "Overall", "NSEEKS", "MEAN", "MEDIAN", "MODE");
+ output_seek_mode_info(ofp, &seek_info);
+ fprintf(ofp, "\n");
+ }
+ fprintf(ofp, "\n");
+}
+
+void output_dip_q2q_seek_info(FILE *ofp)
+{
+ n_seeks = 1;
+ memset(&seek_info, 0, sizeof(seek_info));
+
+ fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n", "DEV", "NSEEKS",
+ "MEAN", "MEDIAN", "MODE");
+ fprintf(ofp, "---------- | --------------- --------------- --------------- | ---------------\n");
+ dip_foreach_out(__output_dip_q2q_seek_info, ofp);
+ if (n_seeks > 1) {
+ fprintf(ofp, "---------- | --------------- --------------- --------------- | ---------------\n");
+ fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n",
+ "Overall", "NSEEKS", "MEAN", "MEDIAN", "MODE");
+ output_seek_mode_info(ofp, &seek_info);
+ fprintf(ofp, "\n");
+ }
fprintf(ofp, "\n");
}
fprintf(ofp, "\n");
}
-int output_avgs(FILE *ofp)
+int n_plugs;
+struct plug_info {
+ long n_plugs, n_timer_unplugs;
+ double t_percent;
+} plug_info;
+
+void __dip_output_plug(struct d_info *dip, void *arg)
+{
+ char dev_info[15];
+ FILE *ofp = arg;
+ double delta, pct;
+
+ if (dip->nplugs > 0) {
+ if (dip->is_plugged) dip_unplug(dip->device, dip->end_time, 0);
+ delta = dip->end_time - dip->start_time;
+ pct = 100.0 * ((dip->plugged_time / delta) / delta);
+
+ fprintf(ofp, "%10s | %10d(%10d) | %13.9lf%%\n",
+ make_dev_hdr(dev_info, 15, dip),
+ dip->nplugs, dip->n_timer_unplugs, pct);
+
+ n_plugs++;
+ plug_info.n_plugs += dip->nplugs;
+ plug_info.n_timer_unplugs += dip->n_timer_unplugs;
+ plug_info.t_percent += pct;
+ }
+}
+
+void __dip_output_plug_all(FILE *ofp, struct plug_info *p)
+{
+ fprintf(ofp, "---------- | ---------- ---------- | ----------------\n");
+ fprintf(ofp, "%10s | %10s %10s | %s\n",
+ "Overall", "# Plugs", "# Timer Us", "% Time Q Plugged");
+ fprintf(ofp, "%10s | %10ld(%10ld) | %13.9lf%%\n", "Average",
+ p->n_plugs / n_plugs, p->n_timer_unplugs / n_plugs,
+ p->t_percent / n_plugs);
+
+}
+
+void output_plug_info(FILE *ofp)
+{
+ fprintf(ofp, "%10s | %10s %10s | %s\n",
+ "DEV", "# Plugs", "# Timer Us", "% Time Q Plugged");
+ fprintf(ofp, "---------- | ---------- ---------- | ----------------\n");
+ dip_foreach_out(__dip_output_plug, ofp);
+ if (n_plugs > 1)
+ __dip_output_plug_all(ofp, &plug_info);
+ fprintf(ofp, "\n");
+}
+
+int n_actQs;
+struct actQ_info {
+ __u64 t_qs;
+ __u64 t_act_qs;
+} actQ_info;
+
+void __dip_output_actQ(struct d_info *dip, void *arg)
+{
+ if (dip->n_qs > 0 && !remapper_dev(dip->device)) {
+ char dev_info[15];
+ double a_actQs = (double)dip->t_act_q / (double)dip->n_qs;
+
+ fprintf((FILE *)arg, "%10s | %13.1lf\n",
+ make_dev_hdr(dev_info, 15, dip), a_actQs);
+
+ n_actQs++;
+ actQ_info.t_qs += dip->n_qs;
+ actQ_info.t_act_qs += dip->t_act_q;
+ }
+}
+
+void __dip_output_actQ_all(FILE *ofp, struct actQ_info *p)
+{
+ fprintf(ofp, "---------- | -------------\n");
+ fprintf(ofp, "%10s | %13s\n", "Overall", "Avgs Reqs @ Q");
+ fprintf(ofp, "%10s | %13.1lf\n", "Average",
+ (double)p->t_act_qs / (double)p->t_qs);
+}
+
+void output_actQ_info(FILE *ofp)
{
- if (exes == NULL || *exes != '\0') {
- output_section_hdr(ofp, "Per Process");
- output_pip_avg(ofp, "Q2Q", pip_q2q_avg);
- output_pip_avg(ofp, "Q2A", pip_q2a_avg);
- output_pip_avg(ofp, "Q2I", pip_q2i_avg);
- output_pip_avg(ofp, "I2D", pip_i2d_avg);
- output_pip_avg(ofp, "D2C", pip_d2c_avg);
- output_pip_avg(ofp, "Q2C", pip_q2c_avg);
+ fprintf(ofp, "%10s | %13s\n", "DEV", "Avg Reqs @ Q");
+ fprintf(ofp, "---------- | -------------\n");
+ dip_foreach_out(__dip_output_actQ, ofp);
+ if (n_actQs > 1)
+ __dip_output_actQ_all(ofp, &actQ_info);
+ fprintf(ofp, "\n");
+}
+
+void output_histos(void)
+{
+ int i;
+ FILE *ofp;
+ char fname[256];
+
+ if (output_name == NULL) return;
+
+ sprintf(fname, "%s_qhist.dat", output_name);
+ ofp = fopen(fname, "w");
+ if (!ofp) {
+ perror(fname);
+ return;
}
- output_section_hdr(ofp, "Per Device");
- output_dip_avg(ofp, "Q2Q", dip_q2q_avg);
- output_dip_avg(ofp, "Q2A", dip_q2a_avg);
- output_dip_avg(ofp, "Q2I", dip_q2i_avg);
- output_dip_avg(ofp, "I2D", dip_i2d_avg);
- output_dip_avg(ofp, "D2C", dip_d2c_avg);
- output_dip_avg(ofp, "Q2C", dip_q2c_avg);
+ fprintf(ofp, "# BTT histogram data\n");
+ fprintf(ofp, "# Q buckets\n");
+ for (i = 0; i < (N_HIST_BKTS-1); i++)
+ fprintf(ofp, "%4d %lld\n", (i+1), (long long)q_histo[i]);
+ fprintf(ofp, "\n# Q bucket for > %d\n%4d %lld\n", (int)N_HIST_BKTS-1,
+ N_HIST_BKTS-1, (long long)q_histo[N_HIST_BKTS-1]);
+ fclose(ofp);
+
+ sprintf(fname, "%s_dhist.dat", output_name);
+ ofp = fopen(fname, "w");
+ if (!ofp) {
+ perror(fname);
+ return;
+ }
+ fprintf(ofp, "# D buckets\n");
+ for (i = 0; i < (N_HIST_BKTS-1); i++)
+ fprintf(ofp, "%4d %lld\n", (i+1), (long long)d_histo[i]);
+ fprintf(ofp, "\n# D bucket for > %d\n%4d %lld\n", (int)N_HIST_BKTS-1,
+ N_HIST_BKTS-1, (long long)d_histo[N_HIST_BKTS-1]);
+ fclose(ofp);
+}
+
+int output_avgs(FILE *ofp)
+{
+ if (output_all_data) {
+ if (exes == NULL || *exes != '\0') {
+ output_section_hdr(ofp, "Per Process");
+ output_pip_avg(ofp, "Q2Q", pip_q2q_avg);
+ output_pip_avg(ofp, "Q2A", pip_q2a_avg);
+ output_pip_avg(ofp, "Q2I", pip_q2i_avg);
+ output_pip_avg(ofp, "I2D", pip_i2d_avg);
+ output_pip_avg(ofp, "D2C", pip_d2c_avg);
+ output_pip_avg(ofp, "Q2C", pip_q2c_avg);
+ }
+
+ output_section_hdr(ofp, "Per Device");
+ output_dip_avg(ofp, "Q2Q", dip_q2q_avg);
+ output_dip_avg(ofp, "Q2A", dip_q2a_avg);
+ output_dip_avg(ofp, "Q2I", dip_q2i_avg);
+ output_dip_avg(ofp, "I2D", dip_i2d_avg);
+ output_dip_avg(ofp, "D2C", dip_d2c_avg);
+ output_dip_avg(ofp, "Q2C", dip_q2c_avg);
+ }
output_section_hdr(ofp, "All Devices");
output_hdr(ofp, "ALL");
__output_avg(ofp, "I2D", &all_avgs.i2d);
__output_avg(ofp, "D2C", &all_avgs.d2c);
__output_avg(ofp, "Q2C", &all_avgs.q2c);
+ fprintf(ofp, "\n");
- if (exes == NULL || *exes != '\0') {
- output_section_hdr(ofp, "Per Process (avgs)");
- output_pip_avgs(ofp);
- }
+ output_section_hdr(ofp, "Device Overhead");
+ output_dip_prep_ohead(ofp);
- output_section_hdr(ofp, "Per Device (avgs)");
- output_dip_avgs(ofp);
+ if (output_all_data) {
+ if (exes == NULL || *exes != '\0') {
+ output_section_hdr(ofp, "Per Process (avgs)");
+ output_pip_avgs(ofp);
+ }
+
+ output_section_hdr(ofp, "Per Device (avgs)");
+ output_dip_avgs(ofp);
+ }
output_section_hdr(ofp, "Device Merge Information");
output_dip_merge_ratio(ofp);
- output_section_hdr(ofp, "Device Overhead");
- output_dip_prep_ohead(ofp);
+ output_section_hdr(ofp, "Device Q2Q Seek Information");
+ output_dip_q2q_seek_info(ofp);
- output_section_hdr(ofp, "Device Seek Information");
+ output_section_hdr(ofp, "Device D2D Seek Information");
output_dip_seek_info(ofp);
+ output_section_hdr(ofp, "Plug Information");
+ output_plug_info(ofp);
+
+ output_section_hdr(ofp, "Active Requests At Q Information");
+ output_actQ_info(ofp);
+
+ output_histos();
+
+ if (output_all_data) {
+ output_section_hdr(ofp, "Q2D Histogram");
+ output_q2d_histo(ofp);
+ }
+
return 0;
}
int output_regions(FILE *ofp, char *header, struct region_info *reg,
float base)
{
- if (reg->qr_cur != NULL)
- list_add_tail(®->qr_cur->head, ®->qranges);
- if (reg->cr_cur != NULL)
- list_add_tail(®->cr_cur->head, ®->cranges);
-
if (list_len(®->qranges) == 0 && list_len(®->cranges) == 0)
return 0;