/*
 * Copyright 2016 The Android Open Source Project
 *
 * Licensed 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 ART_COMPILER_JIT_JIT_LOGGER_H_
#define ART_COMPILER_JIT_JIT_LOGGER_H_

#include <memory>

#include "base/mutex.h"
#include "base/os.h"
#include "compiled_method.h"

namespace art {

class ArtMethod;

namespace jit {

//
// JitLogger supports two approaches of perf profiling.
//
// (1) perf-map:
//     The perf-map mechanism generates perf-PID.map file,
//     which provides simple "address, size, method_name" information to perf,
//     and allows perf to map samples in jit-code-cache to jitted method symbols.
//
//     Command line Example:
//       $ perf record dalvikvm -Xcompiler-option --generate-debug-info -cp <classpath> Test
//       $ perf report
//     NOTE:
//       - Make sure that the perf-PID.map file is available for 'perf report' tool to access,
//         so that jitted method can be displayed.
//
//
// (2) perf-inject:
//     The perf-inject mechansim generates jit-PID.dump file,
//     which provides rich informations about a jitted method.
//     It allows perf or other profiling tools to do advanced analysis on jitted code,
//     for example instruction level profiling.
//
//     Command line Example:
//       $ perf record -k mono dalvikvm -Xcompiler-option --generate-debug-info -cp <classpath> Test
//       $ perf inject -i perf.data -o perf.data.jitted
//       $ perf report -i perf.data.jitted
//       $ perf annotate -i perf.data.jitted
//     NOTE:
//       REQUIREMENTS
//       - The 'perf record -k mono' option requires 4.1 (or higher) Linux kernel.
//       - The 'perf inject' (generating jit ELF files feature) requires perf 4.6 (or higher).
//       PERF RECORD
//       - The '-k mono' option tells 'perf record' to use CLOCK_MONOTONIC clock during sampling;
//         which is required by 'perf inject', to make sure that both perf.data and jit-PID.dump
//         have unified clock source for timestamps.
//       PERF INJECT
//       - The 'perf inject' tool injects information from jit-PID.dump into perf.data file,
//         and generates small ELF files (jitted-TID-CODEID.so) for each jitted method.
//       - On Android devices, the jit-PID.dump file is generated in /data/misc/trace/ folder, and
//         such location is recorded in perf.data file.
//         The 'perf inject' tool is going to look for jit-PID.dump and generates small ELF files in
//         this /data/misc/trace/ folder.
//         Make sure that you have the read/write access to /data/misc/trace/ folder.
//       - On non-Android devices, the jit-PID.dump file is generated in /tmp/ folder, and
//         'perf inject' tool operates on this folder.
//         Make sure that you have the read/write access to /tmp/ folder.
//       - If you are executing 'perf inject' on non-Android devices (host), but perf.data and
//         jit-PID.dump files are adb-pulled from Android devices, make sure that there is a
//         /data/misc/trace/ folder on host, and jit-PID.dump file is copied to this folder.
//       - Currently 'perf inject' doesn't provide option to change the path for jit-PID.dump and
//         generated ELF files.
//       PERF ANNOTATE
//       - The 'perf annotate' tool displays assembly level profiling report.
//         Source code can also be displayed if the ELF file has debug symbols.
//       - Make sure above small ELF files are available for 'perf annotate' tool to access,
//         so that jitted code can be displayed in assembly view.
//
class JitLogger {
 public:
    JitLogger() : code_index_(0), marker_address_(nullptr) {}

    void OpenLog() {
      OpenPerfMapLog();
      OpenJitDumpLog();
    }

    void WriteLog(const void* ptr, size_t code_size, ArtMethod* method)
        REQUIRES_SHARED(Locks::mutator_lock_) {
      WritePerfMapLog(ptr, code_size, method);
      WriteJitDumpLog(ptr, code_size, method);
    }

    void CloseLog() {
      ClosePerfMapLog();
      CloseJitDumpLog();
    }

 private:
    // For perf-map profiling
    void OpenPerfMapLog();
    void WritePerfMapLog(const void* ptr, size_t code_size, ArtMethod* method)
        REQUIRES_SHARED(Locks::mutator_lock_);
    void ClosePerfMapLog();

    // For perf-inject profiling
    void OpenJitDumpLog();
    void WriteJitDumpLog(const void* ptr, size_t code_size, ArtMethod* method)
        REQUIRES_SHARED(Locks::mutator_lock_);
    void CloseJitDumpLog();

    void OpenMarkerFile();
    void CloseMarkerFile();
    void WriteJitDumpHeader();
    void WriteJitDumpDebugInfo();

    std::unique_ptr<File> perf_file_;
    std::unique_ptr<File> jit_dump_file_;
    uint64_t code_index_;
    void* marker_address_;

    DISALLOW_COPY_AND_ASSIGN(JitLogger);
};

}  // namespace jit
}  // namespace art

#endif  // ART_COMPILER_JIT_JIT_LOGGER_H_
