Skip to content

Commit

Permalink
feat(sampling): JIT support via perf-[PID].map files
Browse files Browse the repository at this point in the history
  • Loading branch information
cvonelm committed Aug 19, 2024
1 parent fdc47af commit 20b010a
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 6 deletions.
9 changes: 9 additions & 0 deletions include/lo2s/address.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,5 +150,14 @@ struct Range

return end <= other.start;
}

bool in(Address addr) const
{
if (addr > start && addr <= end)
{
return true;
}
return false;
}
};
} // namespace lo2s
12 changes: 6 additions & 6 deletions include/lo2s/line_info.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ struct LineInfo
private:
static constexpr unsigned int UNKNOWN_LINE = 0;

LineInfo(const char* file, const char* function, unsigned int line, const std::string& dso)
: file(file), function(function), line((line != UNKNOWN_LINE) ? line : 1), dso(dso)
{
}

public:
// Note: If line is not known, we write 1 anyway so the rest is shown in vampir
// phijor 2018-11-08: I think this workaround is not needed anymore? vampir
// shows source code locations with line == 0 just fine.
Expand All @@ -39,12 +45,6 @@ struct LineInfo
{
}

LineInfo(const char* file, const char* function, unsigned int line, const std::string& dso)
: file(file), function(function), line((line != UNKNOWN_LINE) ? line : 1), dso(dso)
{
}

public:
static LineInfo for_function(const char* file, const char* function, unsigned int line,
const std::string& dso)
{
Expand Down
140 changes: 140 additions & 0 deletions include/lo2s/perf_map_resolve.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* This file is part of the lo2s software.
* Linux OTF2 sampling
*
* Copyright (c) 2016,
* Technische Universitaet Dresden, Germany
*
* lo2s is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* lo2s is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with lo2s. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <fmt/core.h>
#include <lo2s/address.hpp>
#include <lo2s/line_info.hpp>
#include <lo2s/log.hpp>

namespace lo2s
{
class PerfMap
{
public:
PerfMap(pid_t pid)
{
Log::error() << "Opening Perf Map for: " << pid;
std::ifstream perf_map_file(fmt::format("/tmp/perf-{}.map", pid));

std::string line;
while (std::getline(perf_map_file, line))
{
// Entries in the perf-[PID].map file have the form:
// START SIZE SYMBOL
// Example:
// ff00ff deadbeef py::foo
std::regex perf_map_regex("([0-9a-f]+) ([0-9a-f]+) (.+)");
std::smatch perf_map_match;

if (std::regex_match(line, perf_map_match, perf_map_regex))
{
LineInfo info = LineInfo::for_unknown_function();
Address start(perf_map_match[1]);
Address end(start + Address(perf_map_match[2]));

// python mapfiles have the symbols in the form
// py::[functioname]:[filename]
std::regex python_regex("py::(.+):(.+)");
std::smatch python_match;

std::string symbol_string = perf_map_match[3].str();

if (std::regex_match(symbol_string, python_match, python_regex))
{
// symbols where the filename starts with '<' (e.g '<frozen os>')
// are compiled into the Python interpreter
if (python_match[2].str()[0] == '<')
{
std::string dso = python_match[2];
std::string function = python_match[1];
info = LineInfo("<unknown file>", function, 0, dso);
}
else
{
std::string function = python_match[1];
std::string filename = python_match[2];
info = LineInfo(filename, function, 0, filename);
}
}
else
{
info = LineInfo("<unknown file>", symbol_string, 0, "<jit>");
}
symbols_.emplace(Range(start, end), info);
}
}
}

LineInfo lookup(Address addr) const
{
for (const auto& symbol : symbols_)
{
if (symbol.first.in(addr))
{
return symbol.second;
}
if (symbol.first.end > addr)
{
break;
}
}
return LineInfo::for_unknown_function();
}

private:
std::map<Range, LineInfo> symbols_;
};

class PerfMapCache
{
public:
static PerfMapCache& instance()
{
static PerfMapCache cache;
return cache;
}

LineInfo lookup_line_info(pid_t pid, Address addr)
{
Log::error() << "Looking up: " << addr;
if (maps_.count(pid))
{
return maps_.at(pid).lookup(addr);
}
else
{
auto res = maps_.emplace(std::piecewise_construct, std::forward_as_tuple(pid),
std::forward_as_tuple(pid));

return res.first->second.lookup(addr);
}
}

private:
PerfMapCache()
{
}

std::map<pid_t, PerfMap> maps_;
};
} // namespace lo2s
6 changes: 6 additions & 0 deletions src/trace/trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <lo2s/monitor/main_monitor.hpp>
#include <lo2s/perf/bio/block_device.hpp>
#include <lo2s/perf/tracepoint/format.hpp>
#include <lo2s/perf_map_resolve.hpp>
#include <lo2s/summary.hpp>
#include <lo2s/syscalls.hpp>
#include <lo2s/time/time.hpp>
Expand Down Expand Up @@ -600,12 +601,17 @@ void Trace::merge_ips(const IpRefMap& new_children, IpCctxMap& children,
auto& local_children = elem.second.children;
LineInfo line_info = LineInfo::for_unknown_function();

PerfMapCache& cache = PerfMapCache::instance();
auto info_it = infos.find(process);
if (info_it != infos.end())
{
MemoryMap maps = info_it->second.maps();
line_info = maps.lookup_line_info(ip);
}
if (line_info == LineInfo::for_unknown_function())
{
line_info = cache.lookup_line_info(process.as_pid_t(), ip);
}

Log::trace() << "resolved " << ip << ": " << line_info;
auto cctx_it = children.find(ip);
Expand Down

0 comments on commit 20b010a

Please sign in to comment.