blob: 04967fd03e6b2838602d9594f189436faae2838f [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#ifndef IMPALA_CODEGEN_JIT_SYMBOL_EMITTER_H
#define IMPALA_CODEGEN_JIT_SYMBOL_EMITTER_H
#include <boost/thread/locks.hpp>
#include <boost/unordered_map.hpp>
#include <iosfwd>
#include <llvm/ExecutionEngine/JITEventListener.h>
#include "util/spinlock.h"
namespace llvm {
class DIContext;
namespace object {
class SymbolRef;
}
}
namespace impala {
/// Class to emit debug symbols and associated info from jitted object files.
/// The methods of this listener are called whenever the query fragment emits
/// a compiled machine code object. We can then process any debug symbols
/// associated with the code object and emit useful information such as disassembly
/// and symbols for perf profiling.
class CodegenSymbolEmitter : public llvm::JITEventListener {
public:
CodegenSymbolEmitter(std::string id) : id_(id), emit_perf_map_(false) { }
~CodegenSymbolEmitter() { }
/// Write the current contents of 'perf_map_' to /tmp/perf-<pid>.map
/// Atomically updates the current map by writing to a temporary file then moving it.
static void WritePerfMap();
/// Called whenever MCJIT module code is emitted.
void NotifyObjectEmitted(const llvm::object::ObjectFile &obj,
const llvm::RuntimeDyld::LoadedObjectInfo &loaded_obj) override;
/// Called whenever MCJIT module code is freed.
void NotifyFreeingObject(const llvm::object::ObjectFile &obj) override;
void set_emit_perf_map(bool emit_perf_map) { emit_perf_map_ = emit_perf_map; }
void set_asm_path(const std::string& asm_path) { asm_path_ = asm_path; }
private:
struct PerfMapEntry {
std::string symbol;
uint64_t addr;
uint64_t size;
};
/// Process the given 'symbol' with 'size'. For function symbols, append to
/// 'perf_map_entries' if 'emit_perf_map_' is true and write disassembly to 'asm_file'
/// if it is open.
void ProcessSymbol(llvm::DIContext* debug_ctx, const llvm::object::SymbolRef& symbol,
uint64_t size, std::vector<PerfMapEntry>* perf_map_entries,
std::ofstream& asm_file);
/// Implementation of WritePerfMap(). 'perf_map_lock_' must be held by caller.
static void WritePerfMapLocked();
/// Emit disassembly for the function. If symbols are present for the code object,
/// the symbols will be interleaved with the disassembly.
void EmitFunctionAsm(llvm::DIContext* debug_ctx, const std::string& fn_symbol,
uint64_t addr, uint64_t size, std::ofstream& asm_file);
/// Identifier to append to symbols, e.g. a fragment instance id. The identifier is
/// passed by the caller when the CodegenSymbolEmitter is constructed. Without this
/// identifier, many distinct codegen'd functions will have the same symbol.
std::string id_;
/// If true, emit perf map info to /tmp/perf-<pid>.map.
bool emit_perf_map_;
/// File to emit disassembly to. If empty string, don't emit.
std::string asm_path_;
/// Global lock to protect 'perf_map_' and writes to /tmp/perf-<pid>.map.
static SpinLock perf_map_lock_;
/// All current entries that should be emitted into the perf map file.
/// Maps the address of each ObjectFile's data to the symbols in the object.
static boost::unordered_map<const void*, std::vector<PerfMapEntry>> perf_map_;
};
}
#endif