blob: 7113945ea2fb22cb6492e37f34451baa62104802 [file] [log] [blame]
/**
* @file libperf_events/operf_stats.cpp
* Management of operf statistics
*
* @remark Copyright 2012 OProfile authors
* @remark Read the file COPYING
*
* Created on: June 11, 2012
* @author Maynard Johnson
* (C) Copyright IBM Corp. 2012
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
#include <errno.h>
#include "operf_stats.h"
#include "op_get_time.h"
unsigned long operf_stats[OPERF_MAX_STATS];
/**
* operf_print_stats - print out latest statistics to operf.log
*/
using namespace std;
static string create_stats_dir(string const & cur_sampledir);
static void write_throttled_event_files(vector< operf_event_t> const & events,
string const & stats_dir);
static void _write_stats_file(string const & stats_filename, unsigned long lost_sample_count)
{
ofstream stats_file(stats_filename.c_str(), ios_base::out);
if (stats_file.good()) {
stats_file << lost_sample_count;
stats_file.close();
} else {
cerr << "Unable to write to stats file " << stats_filename << endl;
}
}
void operf_print_stats(string sessiondir, char * starttime, bool throttled,
vector< operf_event_t> const & events)
{
string operf_log (sessiondir);
unsigned long total_lost_samples = 0;
bool stats_dir_valid = true;
string stats_dir = create_stats_dir(sessiondir + "/" + "samples/current/");
if (strcmp(stats_dir.c_str(), "") != 0) {
// If there are throttled events print them
write_throttled_event_files(events, stats_dir);
} else {
stats_dir_valid = false;
perror("Unable to create stats dir");
}
operf_log.append("/samples/operf.log");
FILE * fp = fopen(operf_log.c_str(), "a");
if (!fp) {
fprintf(stderr, "Unable to open %s file.\n", operf_log.c_str());
return;
}
fprintf(fp, "\nProfiling started at %s", starttime);
fprintf(fp, "Profiling stopped at %s", op_get_time());
fprintf(fp, "\n-- OProfile/operf Statistics --\n");
fprintf(fp, "Nr. non-backtrace samples: %lu\n", operf_stats[OPERF_SAMPLES]);
fprintf(fp, "Nr. kernel samples: %lu\n", operf_stats[OPERF_KERNEL]);
fprintf(fp, "Nr. user space samples: %lu\n", operf_stats[OPERF_PROCESS]);
fprintf(fp, "Nr. samples lost due to sample address not in expected range for domain: %lu\n",
operf_stats[OPERF_INVALID_CTX]);
fprintf(fp, "Nr. lost kernel samples: %lu\n", operf_stats[OPERF_LOST_KERNEL]);
fprintf(fp, "Nr. samples lost due to sample file open failure: %lu\n",
operf_stats[OPERF_LOST_SAMPLEFILE]);
fprintf(fp, "Nr. samples lost due to no permanent mapping: %lu\n",
operf_stats[OPERF_LOST_NO_MAPPING]);
fprintf(fp, "Nr. user context kernel samples lost due to no app info available: %lu\n",
operf_stats[OPERF_NO_APP_KERNEL_SAMPLE]);
fprintf(fp, "Nr. user samples lost due to no app info available: %lu\n",
operf_stats[OPERF_NO_APP_USER_SAMPLE]);
fprintf(fp, "Nr. backtraces skipped due to no file mapping: %lu\n",
operf_stats[OPERF_BT_LOST_NO_MAPPING]);
fprintf(fp, "Nr. hypervisor samples dropped due to address out-of-range: %lu\n",
operf_stats[OPERF_LOST_INVALID_HYPERV_ADDR]);
fprintf(fp, "Nr. samples lost reported by perf_events kernel: %lu\n",
operf_stats[OPERF_RECORD_LOST_SAMPLE]);
if (operf_stats[OPERF_RECORD_LOST_SAMPLE]) {
fprintf(stderr, "\n\n * * * ATTENTION: The kernel lost %lu samples. * * *\n",
operf_stats[OPERF_RECORD_LOST_SAMPLE]);
fprintf(stderr, "Decrease the sampling rate to eliminate (or reduce) lost samples.\n");
} else if (throttled) {
fprintf(stderr, "* * * * WARNING: Profiling rate was throttled back by the kernel * * * *\n");
fprintf(stderr, "The number of samples actually recorded is less than expected, but is\n");
fprintf(stderr, "probably still statistically valid. Decreasing the sampling rate is the\n");
fprintf(stderr, "best option if you want to avoid throttling.\n");
}
for (int i = OPERF_INDEX_OF_FIRST_LOST_STAT; i < OPERF_MAX_STATS; i++) {
if (stats_dir_valid && operf_stats[i])
_write_stats_file(stats_dir + "/" + stats_filenames[i], operf_stats[i]);
total_lost_samples += operf_stats[i];
}
// Write total_samples into stats file if we see any indication of lost samples
if (total_lost_samples)
_write_stats_file(stats_dir + "/" + stats_filenames[OPERF_SAMPLES], operf_stats[OPERF_SAMPLES]);
if (total_lost_samples > (int)(OPERF_WARN_LOST_SAMPLES_THRESHOLD
* operf_stats[OPERF_SAMPLES]))
fprintf(stderr, "\nWARNING: Lost samples detected! See %s for details.\n", operf_log.c_str());
fflush(fp);
fclose(fp);
};
static void write_throttled_event_files(vector< operf_event_t> const & events,
string const & stats_dir)
{
string outputfile;
ofstream outfile;
string event_name;
string throttled_dir;
bool throttled_dir_created = false;
int rc;
throttled_dir = stats_dir + "/throttled";
for (unsigned index = 0; index < events.size(); index++) {
if (events[index].throttled == true) {
if (!throttled_dir_created) {
rc = mkdir(throttled_dir.c_str(),
S_IRWXU | S_IRWXG
| S_IROTH | S_IXOTH);
if (rc && (errno != EEXIST)) {
cerr << "Error trying to create " << throttled_dir
<< endl;
perror("mkdir failed with");
return;
}
throttled_dir_created = true;
}
/* Write file entry to indicate if the data sample was
* throttled.
*/
outputfile = throttled_dir + "/"
+ events[index].name;
outfile.open(outputfile.c_str());
if (!outfile.is_open()) {
cerr << "Internal error: Could not create " << outputfile
<< strerror(errno) << endl;
} else {
outfile.close();
}
}
}
if (throttled_dir_created) {
cerr << "\nWARNING! Some of the events were throttled. "
<< "Throttling occurs when\n";
cerr << "the initial sample rate is too high, causing an "
<< "excessive number of\n";
cerr << "interrupts. Decrease the sampling frequency. "
<< "Check the directory\n";
cerr << throttled_dir << "\n"
<< "for the throttled event names.\n\n";
}
};
static string create_stats_dir(string const & cur_sampledir)
{
int rc;
std::string stats_dir;
/* Assumption: cur_sampledir ends in slash */
stats_dir = cur_sampledir + "stats";
rc = mkdir(stats_dir.c_str(),
S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (rc && (errno != EEXIST)) {
cerr << "Error trying to create stats dir. " << endl;
perror("mkdir failed with");
return NULL;
}
return stats_dir;
}