char **debuginfo_file_name __attribute__((unused)))
{
#ifdef DEBUG_MODULES
- cerr << "nop_find_debuginfo: modname=" << modname << " file_name=" << file_name << " debuglink_file=" << debuglink_file << endl;
+ cerr << format("nop_find_debuginfo: modname={} file_name={} debuglink_file={}\n", modname, file_name, debuglink_file);
#endif
return -1;
}
// Unwind statistics for a Dwfl and associated process.
struct UnwindDwflStats {
Dwfl *dwfl;
- std::string comm;
+ string comm;
int max_frames; /* for diagnostic purposes */
int total_samples; /* for diagnostic purposes */
int lost_samples; /* for diagnostic purposes */
histogram[pc]++;
}
void record_callgraph_arc(Dwarf_Addr from, Dwarf_Addr to) {
- std::pair<uint64_t, uint64_t> arc(from, to);
+ pair<uint64_t, uint64_t> arc(from, to);
if (callgraph.count(arc) == 0)
callgraph[arc]=1;
else
UnwindDwflStats *pid_find(pid_t pid);
UnwindDwflStats *pid_find_or_create(pid_t pid);
- const char *pid_find_comm(pid_t pid);
+ string pid_find_comm(pid_t pid);
Dwfl *pid_find_dwfl(pid_t pid);
void pid_store_dwfl(pid_t pid, Dwfl *dwfl);
virtual void process(const perf_event_header* sample) {}
virtual void process_comm(const perf_event_header* sample,
- uint32_t pid, uint32_t tid, bool exec, const char* comm) {}
+ uint32_t pid, uint32_t tid, bool exec, const string& comm) {}
virtual void process_exit(const perf_event_header* sample,
uint32_t pid, uint32_t ppid,
uint32_t tid, uint32_t ptid) {}
StatsPerfConsumer() {}
~StatsPerfConsumer(); // report to stdout
void process_comm(const perf_event_header* sample,
- uint32_t pid, uint32_t tid, bool exec, const char* comm);
+ uint32_t pid, uint32_t tid, bool exec, const string& comm);
void process_exit(const perf_event_header* sample,
uint32_t pid, uint32_t ppid,
uint32_t tid, uint32_t ptid);
int unwind_frame_cb(Dwfl_Frame *state);
void process_comm(const perf_event_header* sample,
- uint32_t pid, uint32_t tid, bool exec, const char* comm);
+ uint32_t pid, uint32_t tid, bool exec, const string& comm);
void process_exit(const perf_event_header* sample,
uint32_t pid, uint32_t ppid,
uint32_t tid, uint32_t ptid);
UnwindStatsTable *stats;
unordered_map<string, string> buildid_to_mainfile;
unordered_map<string, string> buildid_to_debugfile;
- void record_gmon_hist(std::ostream &of, map<uint64_t, uint32_t> &histogram, uint64_t low_pc, uint64_t high_pc, uint64_t alignment);
+ void record_gmon_hist(ostream &of, map<uint64_t, uint32_t> &histogram, uint64_t low_pc, uint64_t high_pc, uint64_t alignment);
public:
GprofUnwindSampleConsumer(UnwindStatsTable *usc) : stats(usc) {}
pfm_err_t rc = pfm_initialize();
if (rc != PFM_SUCCESS)
{
- cerr << "ERROR: pfm_initialized failed"
- << ": " << pfm_strerror(rc) << endl;
+ cerr << format("ERROR: pfm_initialized failed: {}\n", pfm_strerror(rc));
exit(1);
}
{
ret = pfm_get_event_info(i, PFM_OS_PERF_EVENT_EXT, &info);
if (ret == PFM_SUCCESS)
- clog << pinfo.name << "::" << info.name << endl;
+ clog << format("{}::{}\n", pinfo.name, info.name);
}
}
}
if (pid > 0 && remaining < argc) // got a pid AND a cmd? reject
{
- cerr << "ERROR: Must not specify both -p PID and CMD" << endl;
+ cerr << format("ERROR: Must not specify both -p PID and CMD\n");
exit(1);
}
pfm_err_t rc = pfm_initialize();
if (rc != PFM_SUCCESS)
{
- cerr << "ERROR: pfm_initialized failed"
- << ": " << pfm_strerror(rc) << endl;
+ cerr << format("ERROR: pfm_initialized failed: {}\n", pfm_strerror(rc));
exit(1);
}
char* fstr = nullptr;
PFM_OS_PERF_EVENT_EXT, &arg);
if (rc != PFM_SUCCESS)
{
- cerr << "ERROR: pfm_get_os_event_encoding failed"
- << ": " << pfm_strerror(rc) << endl;
+ cerr << format("ERROR: pfm_get_os_event_encoding failed: {}\n", pfm_strerror(rc));
exit(1);
}
if (verbose)
{
- clog << "libpfm expanded " << libpfm_event << " to " << fstr << endl;
+ clog << format("libpfm expanded {} to {}\n", libpfm_event, fstr);
}
libpfm_event_decoded = fstr; // overwrite
free(fstr);
int rc = pipe (pipefd); // will use pipefd[] >= 0 as flag for synchronization just below
if (rc < 0)
{
- cerr << "ERROR: pipe failed"
- << ": " << strerror(errno) << endl;
+ cerr << format("ERROR: pipe failed: {}\n", strerror(errno));
exit(1);
}
int rc = read (pipefd[0], &dummy, 1); // block until parent is ready
if (rc != 1)
{
- cerr << "ERROR: child sync read failed"
- << ": " << strerror(errno) << endl;
+ cerr << format("ERROR: child sync read failed: {}\n", strerror(errno));
exit(1);
}
close (pipefd[0]);
execvp (argv[remaining], & argv[remaining] /* not +1: child argv[0] included! */ );
// notreached unless error
- cerr << "ERROR: execvp failed"
- << ": " << strerror(errno) << endl;
+ cerr << format("ERROR: execvp failed: {}\n", strerror(errno));
exit(1);
}
else if (pid > 0) // in parent
}
else // error
{
- cerr << "ERROR: fork failed"
- << ": " << strerror(errno) << endl;
+ cerr << format("ERROR: fork failed: {}\n", strerror(errno));
exit(1);
}
}
if (verbose)
{
clog << "Starting stack profile collection ";
- if (pid) clog << "pid " << pid;
+ if (pid) clog << format("pid {}", pid);
else clog << "systemwide";
- clog << endl;
+ clog << "\n";
}
while (true) // main loop
}
catch (const exception& e)
{
- cerr << e.what() << endl;
+ cerr << format("{}\n", e.what());
}
return 0;
else if (strcmp(u.machine, "i686") == 0 || strcmp(u.machine, "i386") == 0) em = EM_386;
else if (strcmp(u.machine, "aarch64") == 0 || strcmp(u.machine, "armv7l")) em = EM_ARM;
else {
- cerr << "ERROR: Unsupported architecture: " << u.machine << endl;
+ cerr << format("ERROR: Unsupported architecture: {}\n", u.machine);
exit(1);
}
this->default_ebl = ebl_openbackend_machine(em);
clog << ((x % 8) ? "" : " ")
<< ((x % 32) ? "" : "\n")
<< format("{:02x}", (unsigned)bytes[x]);
- clog << endl;
+ clog << "\n";
}
// Iterate over all cpus, even if attaching to a single pid, because
PERF_FLAG_FD_CLOEXEC);
if (fd < 0)
{
- cerr << "WARNING: unable to open perf event for cpu " << cpu
- << ": " << strerror(errno) << endl;
+ cerr << format("WARNING: unable to open perf event for cpu {}: {}\n", cpu, strerror(errno));
continue;
}
void *buf = mmap(NULL, this->mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == MAP_FAILED)
{
- cerr << "ERROR: perf event mmap failed"
- << ": " << strerror(errno) << endl;
+ cerr << format("ERROR: perf event mmap failed: {}\n", strerror(errno));
close(fd);
continue;
}
// perf event consumers
void StatsPerfConsumer::process_comm(const perf_event_header *sample,
- uint32_t pid, uint32_t tid, bool exec, const char *comm)
+ uint32_t pid, uint32_t tid, bool exec, const string &comm)
{
if (show_events)
{
- clog << "process_comm: pid=" << pid << " tid=" << tid << " exec=" << exec << " comm=" << comm << endl;
+ clog << format("process_comm: pid={} tid={} exec={} comm={}\n", pid, tid, exec, comm);
}
}
{
if (show_events)
{
- clog << "process_exit: pid=" << pid << " ppid=" << ppid << " tid=" << tid << " ptid=" << ptid << endl;
+ clog << format("process_exit: pid={} ppid={} tid={} ptid={}\n", pid, ppid, tid, ptid);
}
}
{
if (show_events)
{
- clog << "process_fork: pid=" << pid << " ppid=" << ppid << " tid=" << tid << " ptid=" << ptid << endl;
+ clog << format("process_fork: pid={} ppid={} tid={} ptid={}\n", pid, ppid, tid, ptid);
}
}
{
for (const auto& kv : this->event_type_counts)
{
- clog << "event type " << kv.first << " count " << kv.second << endl;
+ clog << format("event type {} count {}\n", kv.first, kv.second);
}
}
return &this->dwfl_tab[pid];
}
-static const char *unknown_comm = "<unknown>";
+static const string unknown_comm = "<unknown>";
-const char *UnwindStatsTable::pid_find_comm (pid_t pid)
+string UnwindStatsTable::pid_find_comm (pid_t pid)
{
UnwindDwflStats *entry = this->pid_find_or_create(pid);
if (entry == NULL)
return unknown_comm;
if (!entry->comm.empty())
- return entry->comm.c_str();
- char name[64];
- int i = snprintf (name, sizeof(name), "/proc/%ld/comm", (long) pid);
- FILE *procfile = fopen(name, "r");
- char *buf = NULL;
- size_t linelen = 0;
- if (procfile == NULL)
- goto fail;
- i = getline(&buf, &linelen, procfile);
- if (i < 0)
- {
- free(buf);
- goto fail;
- }
- for (i = linelen - 1; i > 0; i--)
- if (buf[i] == '\n')
- buf[i] = '\0';
-
- entry->comm = buf;
- free(buf);
- fclose(procfile);
- goto done;
- fail:
- entry->comm = unknown_comm;
- done:
- return entry->comm.c_str();
+ return entry->comm;
+ string name = format("/proc/{}/comm", pid);
+ ifstream procfile(name);
+ string buf;
+ if (!procfile || !getline(procfile, buf))
+ entry->comm = unknown_comm;
+ else
+ entry->comm = buf;
+
+ return entry->comm;
}
Dwfl *UnwindStatsTable::pid_find_dwfl (pid_t pid)
to remove some duplication of existing linux-pid-attach code. */
int PerfConsumerUnwinder::find_procfile (Dwfl *dwfl, pid_t *pid, Elf **elf, int *elf_fd)
{
- char buffer[36];
- FILE *procfile;
int err = 0; /* The errno to return. XXX libdwfl would also set this for dwfl->attacherr. */
/* Make sure to report the actual PID (thread group leader) to
dwfl_attach_state. */
- snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) *pid);
- procfile = fopen (buffer, "r");
- if (procfile == NULL)
+ string buffer = format("/proc/{}/status", *pid);
+ ifstream procfile(buffer);
+ if (!procfile)
{
err = errno;
fail:
return err;
}
- char *line = NULL;
- size_t linelen = 0;
- while (getline (&line, &linelen, procfile) >= 0)
- if (startswith (line, "Tgid:"))
+ string line;
+ while (getline (procfile, line))
+ if (startswith (line.c_str(), "Tgid:"))
{
errno = 0;
char *endptr;
- long val = strtol (&line[5], &endptr, 10);
+ long val = strtol (&line.c_str()[5], &endptr, 10);
if ((errno == ERANGE && val == LONG_MAX)
|| *endptr != '\n' || val < 0 || val != (pid_t) val)
*pid = 0;
*pid = (pid_t) val;
break;
}
- free (line);
- fclose(procfile);
if (*pid == 0)
{
goto fail;
}
- char name[64];
- int i = snprintf (name, sizeof (name), "/proc/%ld/task", (long) *pid);
- if (i <= 0 || i >= (ssize_t) sizeof (name) - 1)
- {
- errno = -ENOMEM;
- goto fail;
- }
- DIR *dir = opendir (name);
- if (dir == NULL)
- {
- err = errno;
- goto fail;
- }
- else
- closedir(dir);
+ {
+ string name = format("/proc/{}/task", *pid);
+ DIR *dir = opendir (name.c_str());
+ if (dir == NULL)
+ {
+ err = errno;
+ goto fail;
+ }
+ else
+ closedir(dir);
+ }
- i = snprintf (name, sizeof (name), "/proc/%ld/exe", (long) *pid);
- assert (i > 0 && i < (ssize_t) sizeof (name) - 1);
- *elf_fd = open (name, O_RDONLY);
+ {
+ string name = format("/proc/{}/exe", *pid);
+ *elf_fd = open (name.c_str(), O_RDONLY);
+ }
if (*elf_fd >= 0)
{
*elf = elf_begin (*elf_fd, ELF_C_READ_MMAP, NULL);
to associate the Dwfl with one of the existing Dwfl_Module
ELF images (to know the machine/class backend to use). */
if (verbose)
- cerr << N_("WARNING: find_procfile pid ") << (long long)*pid << ": elf not found" << endl;
+ cerr << format(N_("WARNING: find_procfile pid {}: elf not found\n"), (long long)*pid);
close (*elf_fd);
*elf_fd = -1;
}
if (err < 0)
{
if (verbose)
- cerr << "WARNING: dwfl_linux_proc_report pid " << (long long) pid << ": " << dwfl_errmsg (-1) << endl;
+ cerr << format("WARNING: dwfl_linux_proc_report pid {}: {}\n", (long long) pid, dwfl_errmsg(-1));
return NULL;
}
err = dwfl_report_end (dwfl, NULL, NULL);
if (err != 0)
{
if (verbose)
- cerr << "WARNING: dwfl_report_end pid " << (long long) pid << ": " << dwfl_errmsg (-1) << endl;
+ cerr << format("WARNING: dwfl_report_end pid {}: {}\n", (long long) pid, dwfl_errmsg(-1));
return NULL;
}
if (nregs < expected_frame_nregs(this->reader->ebl()))
{
if (verbose)
- cerr << N_("WARNING: find_dwfl: nregs=") << nregs << ", expected at least " << ebl_frame_nregs(this->reader->ebl()) << endl;
+ cerr << format(N_("WARNING: find_dwfl: nregs={}, expected at least {}\n"), nregs, ebl_frame_nregs(this->reader->ebl()));
return NULL;
}
if (err < 0)
{
if (verbose)
- cerr << "WARNING: find_procfile pid " << (long long) pid << ": " << dwfl_errmsg (-1) << endl;
+ cerr << format("WARNING: find_procfile pid {}: {}\n", (long long) pid, dwfl_errmsg(-1));
return NULL;
}
if (! dwfl_frame_pc (state, &pc, &isactivation))
{
if (verbose)
- cerr << "WARNING: dwfl_frame_pc: " << dwfl_errmsg(-1) << endl;
+ cerr << format("WARNING: dwfl_frame_pc: {}\n", dwfl_errmsg(-1));
return DWARF_CB_ABORT;
}
if (rc < 0)
{
if (verbose)
- cerr << "WARNING: dwfl_frame_reg: " << dwfl_errmsg(-1) << endl;
+ cerr << format("WARNING: dwfl_frame_reg: {}\n", dwfl_errmsg(-1));
return DWARF_CB_ABORT;
}
// real perf consumer: event handler callbacks
void PerfConsumerUnwinder::process_comm(const perf_event_header *sample,
- uint32_t pid, uint32_t tid, bool exec, const char *comm)
+ uint32_t pid, uint32_t tid, bool exec, const string &comm)
{
// XXX: Could have dwflst ditch data for process and start anew, if EXEC.
}
uint32_t nregs, const uint64_t *regs,
uint64_t data_size, const uint8_t *data)
{
- const char *comm = NULL;
+ string comm;
if (show_summary)
comm = this->stats->pid_find_comm(pid);
if (show_frames)
- clog << endl; /* extra newline for padding */
+ clog << "\n"; /* extra newline for padding */
Elf *elf = NULL; // XXX: when is this released?
bool cached = false;
}
if (verbose && show_summary)
{
- cerr << "WARNING: find_dwfl pid " << (long long)pid << " (" << comm << ") (failed)" << endl;
+ cerr << format("WARNING: find_dwfl pid {} ({}) (failed)\n", (long long)pid, comm);
}
else
{
- cerr << "WARNING: find_dwfl pid " << (long long)pid << " (failed)" << endl;
+ cerr << format("WARNING: find_dwfl pid {} (failed)\n", (long long)pid);
}
return;
}
{
if (verbose)
{
- cerr << "WARNING: dwflst_perf_sample_getframes pid " << (long long)pid << ": " << dwfl_errmsg(-1) << endl;
+ cerr << format("WARNING: dwflst_perf_sample_getframes pid {}: {}\n", (long long)pid, dwfl_errmsg(-1));
}
}
if (show_summary)
#define PERCENT(x,tot) ((x+tot == 0)?0.0:((double)x)/((double)tot)*100.0)
int total_samples = 0;
int total_lost_samples = 0;
- clog << endl << "=== pid / sample counts ===" << endl;
+ clog << "\n=== pid / sample counts ===\n";
for (auto& p : this->stats->dwfl_tab)
{
pid_t pid = p.first;
clog << format(N_("TOTAL -- received {} samples, lost {} samples, loaded {} processes\n"),
total_samples, total_lost_samples,
this->stats->dwfl_tab.size() /* TODO: If implementing eviction, need to maintain a separate count of evicted pids. */);
- clog << endl;
+ clog << "\n";
}
}
};
-void GprofUnwindSampleConsumer::record_gmon_hist(std::ostream &of, map<uint64_t, uint32_t> &histogram, uint64_t low_pc, uint64_t high_pc, uint64_t alignment)
+void GprofUnwindSampleConsumer::record_gmon_hist(ostream &of, map<uint64_t, uint32_t> &histogram, uint64_t low_pc, uint64_t high_pc, uint64_t alignment)
{
// write one histogram from low_pc ... high_pc
uint32_t num_buckets = (high_pc-low_pc)/alignment + 1;
if (target_path != unknown_comm) // skip .exe symlink if there's no path
if (symlink(target_path.c_str(), exe_symlink_path.c_str()) == -1) {
// Handle error, e.g., print errno or throw exception
- cerr << "WARNING: symlink failed: " << strerror(errno) << endl;
+ cerr << format("WARNING: symlink failed: {}\n", strerror(errno));
//return; /* TODO(REVIEW.9): We may want to re-create the symlink on repeated runs since deleting the output data is annoying. */
}
json_object *metadata = json_object_new_object();
if (!metadata) {
json_fail:
- cerr << "ERROR: json allocation failed: " << strerror(errno) << endl;
+ cerr << format("ERROR: json allocation failed: {}\n", strerror(errno));
return;
}
json_object *buildid_js = json_object_new_string(buildid.c_str());
GprofUnwindSampleConsumer::~GprofUnwindSampleConsumer()
{
if (show_summary)
- clog << endl << "=== buildid / sample counts ===" << endl;
+ clog << "\n=== buildid / sample counts ===\n";
UnwindStatsTable::buildid_map_t m (this->stats->buildid_tab.begin(), this->stats->buildid_tab.end());
for (auto& p : m) // traverse in sorted order
clog << "===\n";
clog << format(N_("TOTAL -- received {} buildids\n"), this->stats->buildid_tab.size());
}
- clog << endl;
+ clog << "\n";
}
void GprofUnwindSampleConsumer::process(const UnwindSample *sample)
if (verbose)
clog << format(N_("{}: Skipping pc={:x} raw_pc={:x} outside module range start={:x}..end={:x}"),
mainfile == NULL ? "<unknown>" : mainfile,
- pc, last_pc, low_addr, high_addr) << endl;
+ pc, last_pc, low_addr, high_addr) << "\n";
return;
}
(void) i;
if (verbose)
clog << format(N_("{}: Skipping pc={:x} raw_pc={:x} outside module range start={:x}..end={:x}"),
mainfile == NULL ? "<unknown>" : mainfile,
- pc2, last_pc, low_addr, high_addr) << endl;
+ pc2, last_pc, low_addr, high_addr) << "\n";
return;
}
(void) j;