<commit_before>/**
 * @file
 * @brief Implementation of charge propagation module with transient behavior simulation
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "TransientPropagationModule.hpp"

#include <map>
#include <memory>
#include <random>
#include <string>
#include <utility>

#include <Eigen/Core>

#include "core/utils/log.h"
#include "objects/PixelCharge.hpp"
#include "tools/runge_kutta.h"

using namespace allpix;

TransientPropagationModule::TransientPropagationModule(Configuration& config,
                                                       Messenger* messenger,
                                                       std::shared_ptr<Detector> detector)
    : Module(config, detector), detector_(std::move(detector)), messenger_(messenger) {

    // Save detector model
    model_ = detector_->getModel();

    // Require deposits message for single detector:
    messenger_->bindSingle(this, &TransientPropagationModule::deposits_message_, MsgFlags::REQUIRED);

    // Seed the random generator with the module seed
    random_generator_.seed(getRandomSeed());

    // Set default value for config variables
    config_.setDefault<double>("timestep", Units::get(0.01, "ns"));
    config_.setDefault<double>("integration_time", Units::get(25, "ns"));
    config_.setDefault<unsigned int>("charge_per_step", 10);
    config_.setDefault<double>("temperature", 293.15);
    config_.setDefault<bool>("output_plots", false);

    // Copy some variables from configuration to avoid lookups:
    temperature_ = config_.get<double>("temperature");
    timestep_ = config_.get<double>("timestep");
    integration_time_ = config_.get<double>("integration_time");
    output_plots_ = config_.get<bool>("output_plots");

    // Parameterization variables from https://doi.org/10.1016/0038-1101(77)90054-5 (section 5.2)
    electron_Vm_ = Units::get(1.53e9 * std::pow(temperature_, -0.87), "cm/s");
    electron_Ec_ = Units::get(1.01 * std::pow(temperature_, 1.55), "V/cm");
    electron_Beta_ = 2.57e-2 * std::pow(temperature_, 0.66);

    hole_Vm_ = Units::get(1.62e8 * std::pow(temperature_, -0.52), "cm/s");
    hole_Ec_ = Units::get(1.24 * std::pow(temperature_, 1.68), "V/cm");
    hole_Beta_ = 0.46 * std::pow(temperature_, 0.17);

    boltzmann_kT_ = Units::get(8.6173e-5, "eV/K") * temperature_;
}

void TransientPropagationModule::init() {

    auto detector = getDetector();

    // Check for electric field
    if(!detector->hasElectricField()) {
        LOG(WARNING) << "This detector does not have an electric field.";
    }

    if(!detector_->hasWeightingPotential()) {
        throw ModuleError("This module requires a weighting potential.");
    }

    if(output_plots_) {
        induced_charge_histo_ = new TH1D("induced_charge_histo",
                                         "Induced charge per time;Drift time [ns];charge [e]",
                                         static_cast<int>(integration_time_ / timestep_),
                                         0,
                                         static_cast<double>(Units::convert(integration_time_, "ns")));
        induced_charge_e_histo_ = new TH1D("induced_charge_e_histo",
                                           "Induced charge per time;Drift time [ns];charge [e]",
                                           static_cast<int>(integration_time_ / timestep_),
                                           0,
                                           static_cast<double>(Units::convert(integration_time_, "ns")));
        induced_charge_h_histo_ = new TH1D("induced_charge_h_histo",
                                           "Induced charge per time;Drift time [ns];charge [e]",
                                           static_cast<int>(integration_time_ / timestep_),
                                           0,
                                           static_cast<double>(Units::convert(integration_time_, "ns")));
    }
}

void TransientPropagationModule::run(unsigned int) {

    // Create map for all pixels
    std::map<Pixel::Index, Pulse> pixel_map;

    // Loop over all deposits for propagation
    LOG(TRACE) << "Propagating charges in sensor";
    for(auto& deposit : deposits_message_->getData()) {

        // Loop over all charges in the deposit
        unsigned int charges_remaining = deposit.getCharge();

        LOG(DEBUG) << "Set of charge carriers (" << deposit.getType() << ") on "
                   << Units::display(deposit.getLocalPosition(), {"mm", "um"});

        auto charge_per_step = config_.get<unsigned int>("charge_per_step");
        while(charges_remaining > 0) {
            // Define number of charges to be propagated and remove charges of this step from the total
            if(charge_per_step > charges_remaining) {
                charge_per_step = charges_remaining;
            }
            charges_remaining -= charge_per_step;

            // Get position and propagate through sensor
            auto position = deposit.getLocalPosition();

            // Propagate a single charge deposit
            propagate(position, deposit.getType(), charge_per_step, pixel_map);
            LOG(DEBUG) << " Propagated " << charge_per_step << " from " << Units::display(position, {"mm", "um"});
        }
    }

    // Create vector of pixel pulses to return for this detector
    std::vector<PixelCharge> pixel_charges;
    for(auto& pixel_index_pulse : pixel_map) {
        pixel_charges.emplace_back(detector_->getPixel(pixel_index_pulse.first), std::move(pixel_index_pulse.second));
    }

    // Create a new message with pixel pulses
    auto pixel_charge_message = std::make_shared<PixelChargeMessage>(std::move(pixel_charges), detector_);

    // Dispatch the message with pixel charges
    messenger_->dispatchMessage(this, pixel_charge_message);
}

/**
 * Propagation is simulated using a parameterization for the electron mobility. This is used to calculate the electron
 * velocity at every point with help of the electric field map of the detector. A Runge-Kutta integration is applied in
 * multiple steps, adding a random diffusion to the propagating charge every step.
 */
void TransientPropagationModule::propagate(const ROOT::Math::XYZPoint& pos,
                                           const CarrierType& type,
                                           const unsigned int charge,
                                           std::map<Pixel::Index, Pulse>& pixel_map) {

    // Create a runge kutta solver using the electric field as step function
    Eigen::Vector3d position(pos.x(), pos.y(), pos.z());

    // Define a lambda function to compute the carrier mobility
    // NOTE This function is typically the most frequently executed part of the framework and therefore the bottleneck
    auto carrier_mobility = [&](double efield_mag) {
        // Compute carrier mobility from constants and electric field magnitude
        double numerator, denominator;
        if(type == CarrierType::ELECTRON) {
            numerator = electron_Vm_ / electron_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / electron_Ec_, electron_Beta_), 1.0 / electron_Beta_);
        } else {
            numerator = hole_Vm_ / hole_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / hole_Ec_, hole_Beta_), 1.0 / hole_Beta_);
        }
        return numerator / denominator;
    };

    // Define a function to compute the diffusion
    auto carrier_diffusion = [&](double efield_mag, double timestep) -> Eigen::Vector3d {
        double diffusion_constant = boltzmann_kT_ * carrier_mobility(efield_mag);
        double diffusion_std_dev = std::sqrt(2. * diffusion_constant * timestep);

        // Compute the independent diffusion in three
        std::normal_distribution<double> gauss_distribution(0, diffusion_std_dev);
        Eigen::Vector3d diffusion;
        for(int i = 0; i < 3; ++i) {
            diffusion[i] = gauss_distribution(random_generator_);
        }
        return diffusion;
    };

    // Define a lambda function to compute the electron velocity
    auto carrier_velocity = [&](double, Eigen::Vector3d cur_pos) -> Eigen::Vector3d {
        auto raw_field = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(cur_pos));
        // Compute the drift velocity
        Eigen::Vector3d efield(raw_field.x(), raw_field.y(), raw_field.z());

        return static_cast<int>(type) * carrier_mobility(efield.norm()) * efield;
    };

    // Create the runge kutta solver with an RKF5 tableau
    auto runge_kutta = make_runge_kutta(tableau::RK5, carrier_velocity, timestep_, position);

    // Continue propagation until the deposit is outside the sensor
    Eigen::Vector3d last_position = position;
    double last_time = 0;
    bool within_sensor = true;
    while(within_sensor && runge_kutta.getTime() < integration_time_) {

        // Save previous position and time
        last_position = position;
        last_time = runge_kutta.getTime();

        // Execute a Runge Kutta step
        runge_kutta.step();

        // Get the current result
        position = runge_kutta.getValue();

        // Get electric field at current position and fall back to empty field if it does not exist
        auto efield = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(position));

        // Apply diffusion step
        auto diffusion = carrier_diffusion(std::sqrt(efield.Mag2()), timestep_);
        position += diffusion;
        runge_kutta.setValue(position);

        // Check for overshooting outside the sensor and correct for it:
        if(!detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position))) {
            LOG(TRACE) << "Found position outside: "
                       << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"um", "mm"});
            // FIXME this simply changes the z coordinate to be within the sensor - maybe we can be more clever
            if(model_->getSensorSize().z() / 2.0 - position.z() < 0) {
                position = Eigen::Vector3d(position.x(), position.y(), model_->getSensorSize().z() / 2.0 - 1e-9);
            } else if(position.z() - model_->getSensorSize().z() / 2.0 < 0) {
                position = Eigen::Vector3d(position.x(), position.y(), -model_->getSensorSize().z() / 2.0 + 1e-9);
            }
            LOG(TRACE) << "New position: " << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"um", "mm"});
            within_sensor = false;
        }

        // Find the nearest pixel
        auto xpixel = static_cast<int>(std::round(position.x() / model_->getPixelSize().x()));
        auto ypixel = static_cast<int>(std::round(position.y() / model_->getPixelSize().y()));
        LOG(TRACE) << "Moving carriers below pixel "
                   << Pixel::Index(static_cast<unsigned int>(xpixel), static_cast<unsigned int>(ypixel)) << " from "
                   << Units::display(static_cast<ROOT::Math::XYZPoint>(last_position), {"um", "mm"}) << " to "
                   << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"um", "mm"}) << ", "
                   << Units::display(runge_kutta.getTime(), "ns");

        // Loop over NxN pixels:
        for(int x = xpixel - 1; x <= xpixel + 1; x++) {
            for(int y = ypixel - 1; y <= ypixel + 1; y++) {
                // Ignore if out of pixel grid
                if(x < 0 || x >= model_->getNPixels().x() || y < 0 || y >= model_->getNPixels().y()) {
                    LOG(TRACE) << "Pixel (" << x << "," << y << ") skipped, outside the grid";
                    continue;
                }

                Pixel::Index pixel_index(static_cast<unsigned int>(x), static_cast<unsigned int>(y));
                auto ramo = detector_->getWeightingPotential(static_cast<ROOT::Math::XYZPoint>(position), pixel_index);
                auto last_ramo =
                    detector_->getWeightingPotential(static_cast<ROOT::Math::XYZPoint>(last_position), pixel_index);

                // Induced charge on electrode is q_int = q * (phi(x1) - phi(x0))
                auto induced = charge * (ramo - last_ramo);
                LOG(TRACE) << "Pixel " << pixel_index << " dPhi = " << (ramo - last_ramo) << ", induced " << type
                           << " q = " << Units::display(induced, "e");

                // Check if this pulse exists already:
                if(pixel_map.find(pixel_index) == pixel_map.end()) {
                    pixel_map[pixel_index] = Pulse(integration_time_, timestep_);
                }

                // Store induced charge in the respective pixel pulse:
                pixel_map[pixel_index].addCharge(induced, runge_kutta.getTime());

                if(output_plots_ && x == 0 && y == 0) {
                    induced_charge_histo_->Fill(runge_kutta.getTime(), induced);
                    if(type == CarrierType::ELECTRON) {
                        induced_charge_e_histo_->Fill(runge_kutta.getTime(), induced);
                    } else {
                        induced_charge_h_histo_->Fill(runge_kutta.getTime(), induced);
                    }
                }
            }
        }
    }

    // Find proper final position in the sensor
    auto time = runge_kutta.getTime();
    if(!detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position))) {
        auto check_position = position;
        check_position.z() = last_position.z();
        if(position.z() > 0 && detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(check_position))) {
            // Carrier left sensor on the side of the pixel grid, interpolate end point on surface
            auto z_cur_border = std::fabs(position.z() - model_->getSensorSize().z() / 2.0);
            auto z_last_border = std::fabs(model_->getSensorSize().z() / 2.0 - last_position.z());
            auto z_total = z_cur_border + z_last_border;
            position = (z_last_border / z_total) * position + (z_cur_border / z_total) * last_position;
            time = (z_last_border / z_total) * time + (z_cur_border / z_total) * last_time;
        } else {
            // Carrier left sensor on any order border, use last position inside instead
            position = last_position;
            time = last_time;
        }
    }
    LOG(TRACE) << "Time: " << Units::display(time, {"ps", "ns"});
}

void TransientPropagationModule::finalize() {
    if(output_plots_) {
        induced_charge_histo_->Write();
        induced_charge_e_histo_->Write();
        induced_charge_h_histo_->Write();
    }
}
<commit_msg>TransientPropagation: invert sign for different charge carrier types to create correct pulse<commit_after>/**
 * @file
 * @brief Implementation of charge propagation module with transient behavior simulation
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "TransientPropagationModule.hpp"

#include <map>
#include <memory>
#include <random>
#include <string>
#include <utility>

#include <Eigen/Core>

#include "core/utils/log.h"
#include "objects/PixelCharge.hpp"
#include "tools/runge_kutta.h"

using namespace allpix;

TransientPropagationModule::TransientPropagationModule(Configuration& config,
                                                       Messenger* messenger,
                                                       std::shared_ptr<Detector> detector)
    : Module(config, detector), detector_(std::move(detector)), messenger_(messenger) {

    // Save detector model
    model_ = detector_->getModel();

    // Require deposits message for single detector:
    messenger_->bindSingle(this, &TransientPropagationModule::deposits_message_, MsgFlags::REQUIRED);

    // Seed the random generator with the module seed
    random_generator_.seed(getRandomSeed());

    // Set default value for config variables
    config_.setDefault<double>("timestep", Units::get(0.01, "ns"));
    config_.setDefault<double>("integration_time", Units::get(25, "ns"));
    config_.setDefault<unsigned int>("charge_per_step", 10);
    config_.setDefault<double>("temperature", 293.15);
    config_.setDefault<bool>("output_plots", false);

    // Copy some variables from configuration to avoid lookups:
    temperature_ = config_.get<double>("temperature");
    timestep_ = config_.get<double>("timestep");
    integration_time_ = config_.get<double>("integration_time");
    output_plots_ = config_.get<bool>("output_plots");

    // Parameterization variables from https://doi.org/10.1016/0038-1101(77)90054-5 (section 5.2)
    electron_Vm_ = Units::get(1.53e9 * std::pow(temperature_, -0.87), "cm/s");
    electron_Ec_ = Units::get(1.01 * std::pow(temperature_, 1.55), "V/cm");
    electron_Beta_ = 2.57e-2 * std::pow(temperature_, 0.66);

    hole_Vm_ = Units::get(1.62e8 * std::pow(temperature_, -0.52), "cm/s");
    hole_Ec_ = Units::get(1.24 * std::pow(temperature_, 1.68), "V/cm");
    hole_Beta_ = 0.46 * std::pow(temperature_, 0.17);

    boltzmann_kT_ = Units::get(8.6173e-5, "eV/K") * temperature_;
}

void TransientPropagationModule::init() {

    auto detector = getDetector();

    // Check for electric field
    if(!detector->hasElectricField()) {
        LOG(WARNING) << "This detector does not have an electric field.";
    }

    if(!detector_->hasWeightingPotential()) {
        throw ModuleError("This module requires a weighting potential.");
    }

    if(output_plots_) {
        induced_charge_histo_ = new TH1D("induced_charge_histo",
                                         "Induced charge per time;Drift time [ns];charge [e]",
                                         static_cast<int>(integration_time_ / timestep_),
                                         0,
                                         static_cast<double>(Units::convert(integration_time_, "ns")));
        induced_charge_e_histo_ = new TH1D("induced_charge_e_histo",
                                           "Induced charge per time;Drift time [ns];charge [e]",
                                           static_cast<int>(integration_time_ / timestep_),
                                           0,
                                           static_cast<double>(Units::convert(integration_time_, "ns")));
        induced_charge_h_histo_ = new TH1D("induced_charge_h_histo",
                                           "Induced charge per time;Drift time [ns];charge [e]",
                                           static_cast<int>(integration_time_ / timestep_),
                                           0,
                                           static_cast<double>(Units::convert(integration_time_, "ns")));
    }
}

void TransientPropagationModule::run(unsigned int) {

    // Create map for all pixels
    std::map<Pixel::Index, Pulse> pixel_map;

    // Loop over all deposits for propagation
    LOG(TRACE) << "Propagating charges in sensor";
    for(auto& deposit : deposits_message_->getData()) {

        // Loop over all charges in the deposit
        unsigned int charges_remaining = deposit.getCharge();

        LOG(DEBUG) << "Set of charge carriers (" << deposit.getType() << ") on "
                   << Units::display(deposit.getLocalPosition(), {"mm", "um"});

        auto charge_per_step = config_.get<unsigned int>("charge_per_step");
        while(charges_remaining > 0) {
            // Define number of charges to be propagated and remove charges of this step from the total
            if(charge_per_step > charges_remaining) {
                charge_per_step = charges_remaining;
            }
            charges_remaining -= charge_per_step;

            // Get position and propagate through sensor
            auto position = deposit.getLocalPosition();

            // Propagate a single charge deposit
            propagate(position, deposit.getType(), charge_per_step, pixel_map);
            LOG(DEBUG) << " Propagated " << charge_per_step << " from " << Units::display(position, {"mm", "um"});
        }
    }

    // Create vector of pixel pulses to return for this detector
    std::vector<PixelCharge> pixel_charges;
    for(auto& pixel_index_pulse : pixel_map) {
        pixel_charges.emplace_back(detector_->getPixel(pixel_index_pulse.first), std::move(pixel_index_pulse.second));
    }

    // Create a new message with pixel pulses
    auto pixel_charge_message = std::make_shared<PixelChargeMessage>(std::move(pixel_charges), detector_);

    // Dispatch the message with pixel charges
    messenger_->dispatchMessage(this, pixel_charge_message);
}

/**
 * Propagation is simulated using a parameterization for the electron mobility. This is used to calculate the electron
 * velocity at every point with help of the electric field map of the detector. A Runge-Kutta integration is applied in
 * multiple steps, adding a random diffusion to the propagating charge every step.
 */
void TransientPropagationModule::propagate(const ROOT::Math::XYZPoint& pos,
                                           const CarrierType& type,
                                           const unsigned int charge,
                                           std::map<Pixel::Index, Pulse>& pixel_map) {

    // Create a runge kutta solver using the electric field as step function
    Eigen::Vector3d position(pos.x(), pos.y(), pos.z());

    // Define a lambda function to compute the carrier mobility
    // NOTE This function is typically the most frequently executed part of the framework and therefore the bottleneck
    auto carrier_mobility = [&](double efield_mag) {
        // Compute carrier mobility from constants and electric field magnitude
        double numerator, denominator;
        if(type == CarrierType::ELECTRON) {
            numerator = electron_Vm_ / electron_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / electron_Ec_, electron_Beta_), 1.0 / electron_Beta_);
        } else {
            numerator = hole_Vm_ / hole_Ec_;
            denominator = std::pow(1. + std::pow(efield_mag / hole_Ec_, hole_Beta_), 1.0 / hole_Beta_);
        }
        return numerator / denominator;
    };

    // Define a function to compute the diffusion
    auto carrier_diffusion = [&](double efield_mag, double timestep) -> Eigen::Vector3d {
        double diffusion_constant = boltzmann_kT_ * carrier_mobility(efield_mag);
        double diffusion_std_dev = std::sqrt(2. * diffusion_constant * timestep);

        // Compute the independent diffusion in three
        std::normal_distribution<double> gauss_distribution(0, diffusion_std_dev);
        Eigen::Vector3d diffusion;
        for(int i = 0; i < 3; ++i) {
            diffusion[i] = gauss_distribution(random_generator_);
        }
        return diffusion;
    };

    // Define a lambda function to compute the electron velocity
    auto carrier_velocity = [&](double, Eigen::Vector3d cur_pos) -> Eigen::Vector3d {
        auto raw_field = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(cur_pos));
        // Compute the drift velocity
        Eigen::Vector3d efield(raw_field.x(), raw_field.y(), raw_field.z());

        return static_cast<int>(type) * carrier_mobility(efield.norm()) * efield;
    };

    // Create the runge kutta solver with an RKF5 tableau
    auto runge_kutta = make_runge_kutta(tableau::RK5, carrier_velocity, timestep_, position);

    // Continue propagation until the deposit is outside the sensor
    Eigen::Vector3d last_position = position;
    double last_time = 0;
    bool within_sensor = true;
    while(within_sensor && runge_kutta.getTime() < integration_time_) {

        // Save previous position and time
        last_position = position;
        last_time = runge_kutta.getTime();

        // Execute a Runge Kutta step
        runge_kutta.step();

        // Get the current result
        position = runge_kutta.getValue();

        // Get electric field at current position and fall back to empty field if it does not exist
        auto efield = detector_->getElectricField(static_cast<ROOT::Math::XYZPoint>(position));

        // Apply diffusion step
        auto diffusion = carrier_diffusion(std::sqrt(efield.Mag2()), timestep_);
        position += diffusion;
        runge_kutta.setValue(position);

        // Check for overshooting outside the sensor and correct for it:
        if(!detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position))) {
            LOG(TRACE) << "Found position outside: "
                       << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"um", "mm"});
            // FIXME this simply changes the z coordinate to be within the sensor - maybe we can be more clever
            if(model_->getSensorSize().z() / 2.0 - position.z() < 0) {
                position = Eigen::Vector3d(position.x(), position.y(), model_->getSensorSize().z() / 2.0 - 1e-9);
            } else if(position.z() - model_->getSensorSize().z() / 2.0 < 0) {
                position = Eigen::Vector3d(position.x(), position.y(), -model_->getSensorSize().z() / 2.0 + 1e-9);
            }
            LOG(TRACE) << "New position: " << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"um", "mm"});
            within_sensor = false;
        }

        // Find the nearest pixel
        auto xpixel = static_cast<int>(std::round(position.x() / model_->getPixelSize().x()));
        auto ypixel = static_cast<int>(std::round(position.y() / model_->getPixelSize().y()));
        LOG(TRACE) << "Moving carriers below pixel "
                   << Pixel::Index(static_cast<unsigned int>(xpixel), static_cast<unsigned int>(ypixel)) << " from "
                   << Units::display(static_cast<ROOT::Math::XYZPoint>(last_position), {"um", "mm"}) << " to "
                   << Units::display(static_cast<ROOT::Math::XYZPoint>(position), {"um", "mm"}) << ", "
                   << Units::display(runge_kutta.getTime(), "ns");

        // Loop over NxN pixels:
        for(int x = xpixel - 1; x <= xpixel + 1; x++) {
            for(int y = ypixel - 1; y <= ypixel + 1; y++) {
                // Ignore if out of pixel grid
                if(x < 0 || x >= model_->getNPixels().x() || y < 0 || y >= model_->getNPixels().y()) {
                    LOG(TRACE) << "Pixel (" << x << "," << y << ") skipped, outside the grid";
                    continue;
                }

                Pixel::Index pixel_index(static_cast<unsigned int>(x), static_cast<unsigned int>(y));
                auto ramo = detector_->getWeightingPotential(static_cast<ROOT::Math::XYZPoint>(position), pixel_index);
                auto last_ramo =
                    detector_->getWeightingPotential(static_cast<ROOT::Math::XYZPoint>(last_position), pixel_index);

                // Induced charge on electrode is q_int = q * (phi(x1) - phi(x0))
                auto induced = charge * (ramo - last_ramo) * (-static_cast<std::underlying_type<CarrierType>::type>(type));
                LOG(TRACE) << "Pixel " << pixel_index << " dPhi = " << (ramo - last_ramo) << ", induced " << type
                           << " q = " << Units::display(induced, "e");

                // Check if this pulse exists already:
                if(pixel_map.find(pixel_index) == pixel_map.end()) {
                    pixel_map[pixel_index] = Pulse(integration_time_, timestep_);
                }

                // Store induced charge in the respective pixel pulse:
                pixel_map[pixel_index].addCharge(induced, runge_kutta.getTime());

                if(output_plots_ && x == 0 && y == 0) {
                    induced_charge_histo_->Fill(runge_kutta.getTime(), induced);
                    if(type == CarrierType::ELECTRON) {
                        induced_charge_e_histo_->Fill(runge_kutta.getTime(), induced);
                    } else {
                        induced_charge_h_histo_->Fill(runge_kutta.getTime(), induced);
                    }
                }
            }
        }
    }

    // Find proper final position in the sensor
    auto time = runge_kutta.getTime();
    if(!detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(position))) {
        auto check_position = position;
        check_position.z() = last_position.z();
        if(position.z() > 0 && detector_->isWithinSensor(static_cast<ROOT::Math::XYZPoint>(check_position))) {
            // Carrier left sensor on the side of the pixel grid, interpolate end point on surface
            auto z_cur_border = std::fabs(position.z() - model_->getSensorSize().z() / 2.0);
            auto z_last_border = std::fabs(model_->getSensorSize().z() / 2.0 - last_position.z());
            auto z_total = z_cur_border + z_last_border;
            position = (z_last_border / z_total) * position + (z_cur_border / z_total) * last_position;
            time = (z_last_border / z_total) * time + (z_cur_border / z_total) * last_time;
        } else {
            // Carrier left sensor on any order border, use last position inside instead
            position = last_position;
            time = last_time;
        }
    }
    LOG(TRACE) << "Time: " << Units::display(time, {"ps", "ns"});
}

void TransientPropagationModule::finalize() {
    if(output_plots_) {
        induced_charge_histo_->Write();
        induced_charge_e_histo_->Write();
        induced_charge_h_histo_->Write();
    }
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
// LLVM 'OPT' UTILITY
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Transforms/UnifyMethodExitNodes.h"
#include "llvm/Transforms/ConstantMerge.h"
#include "llvm/Transforms/CleanupGCCOutput.h"
#include "llvm/Transforms/LevelChange.h"
#include "llvm/Transforms/MethodInlining.h"
#include "llvm/Transforms/SymbolStripping.h"
#include "llvm/Transforms/ChangeAllocations.h"
#include "llvm/Transforms/IPO/SimpleStructMutation.h"
#include "llvm/Transforms/IPO/GlobalDCE.h"
#include "llvm/Transforms/Scalar/DCE.h"
#include "llvm/Transforms/Scalar/ConstantProp.h"
#include "llvm/Transforms/Scalar/IndVarSimplify.h"
#include "llvm/Transforms/Scalar/InstructionCombining.h"
#include "llvm/Transforms/Scalar/PromoteMemoryToRegister.h"
#include "llvm/Transforms/Instrumentation/TraceValues.h"
#include "Support/CommandLine.h"
#include <fstream>
#include <memory>

// Opts enum - All of the transformations we can do...
enum Opts {
  // Basic optimizations
  dce, constprop, inlining, constmerge, strip, mstrip, mergereturn,

  // Miscellaneous Transformations
  trace, tracem, raiseallocs, cleangcc,

  // Printing and verifying...
  print, verify,

  // More powerful optimizations
  indvars, instcombine, sccp, adce, raise, mem2reg,

  // Interprocedural optimizations...
  globaldce, swapstructs, sortstructs,
};

// New template functions - Provide functions that return passes of specified
// types, with specified arguments...
//
template<class PassClass>
Pass *New() {
  return new PassClass();
}

template<class PassClass, typename ArgTy1, ArgTy1 Arg1>
Pass *New() {
  return new PassClass(Arg1);
}

template<class PassClass, typename ArgTy1, ArgTy1 Arg1,
                          typename ArgTy2, ArgTy1 Arg2>
Pass *New() {
  return new PassClass(Arg1, Arg2);
}

static Pass *NewPrintMethodPass() {
  return new PrintMethodPass("Current Method: \n", &cerr);
}

// OptTable - Correlate enum Opts to Pass constructors...
//
struct {
  enum Opts OptID;
  Pass * (*PassCtor)();
} OptTable[] = {
  { dce        , New<DeadCodeElimination> },
  { constprop  , New<ConstantPropogation> },
  { inlining   , New<MethodInlining> },
  { constmerge , New<ConstantMerge> },
  { strip      , New<SymbolStripping> },
  { mstrip     , New<FullSymbolStripping> },
  { mergereturn, New<UnifyMethodExitNodes> },

  { indvars    , New<InductionVariableSimplify> },
  { instcombine, New<InstructionCombining> },
  { sccp       , New<SCCPPass> },
  { adce       , New<AgressiveDCE> },
  { raise      , New<RaisePointerReferences> },
  { mem2reg    , newPromoteMemoryToRegister },

  { trace      , New<InsertTraceCode, bool, true, bool, true> },
  { tracem     , New<InsertTraceCode, bool, false, bool, true> },
  { print      , NewPrintMethodPass },
  { verify     , createVerifierPass },
  { raiseallocs, New<RaiseAllocations> },
  { cleangcc   , New<CleanupGCCOutput> },
  { globaldce  , New<GlobalDCE> },
  { swapstructs, New<SimpleStructMutation, SimpleStructMutation::Transform,
                     SimpleStructMutation::SwapElements>},
  { sortstructs, New<SimpleStructMutation, SimpleStructMutation::Transform,
                     SimpleStructMutation::SortElements>},
};

// Command line option handling code...
//
cl::String InputFilename ("", "Load <arg> file to optimize", cl::NoFlags, "-");
cl::String OutputFilename("o", "Override output filename", cl::NoFlags, "");
cl::Flag   Force         ("f", "Overwrite output files", cl::NoFlags, false);
cl::Flag   PrintEachXForm("p", "Print module after each transformation");
cl::Flag   Quiet         ("q", "Don't print modifying pass names", 0, false);
cl::Alias  QuietA        ("quiet", "Alias for -q", cl::NoFlags, Quiet);
cl::EnumList<enum Opts> OptimizationList(cl::NoFlags,
  clEnumVal(dce        , "Dead Code Elimination"),
  clEnumVal(constprop  , "Simple constant propogation"),
 clEnumValN(inlining   , "inline", "Method integration"),
  clEnumVal(constmerge , "Merge identical global constants"),
  clEnumVal(strip      , "Strip symbols"),
  clEnumVal(mstrip     , "Strip module symbols"),
  clEnumVal(mergereturn, "Unify method exit nodes"),

  clEnumVal(indvars    , "Simplify Induction Variables"),
  clEnumVal(instcombine, "Combine redundant instructions"),
  clEnumVal(sccp       , "Sparse Conditional Constant Propogation"),
  clEnumVal(adce       , "Agressive DCE"),
  clEnumVal(mem2reg    , "Promote alloca locations to registers"),

  clEnumVal(globaldce  , "Remove unreachable globals"),
  clEnumVal(swapstructs, "Swap structure types around"),
  clEnumVal(sortstructs, "Sort structure elements"),

  clEnumVal(raiseallocs, "Raise allocations from calls to instructions"),
  clEnumVal(cleangcc   , "Cleanup GCC Output"),
  clEnumVal(raise      , "Raise to Higher Level"),
  clEnumVal(trace      , "Insert BB & Method trace code"),
  clEnumVal(tracem     , "Insert Method trace code only"),

  clEnumVal(print      , "Print working method to stderr"),
  clEnumVal(verify     , "Verify module is well formed"),
0);

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");

  // Load the input module...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
  if (M.get() == 0) {
    cerr << "bytecode didn't read correctly.\n";
    return 1;
  }

  // Figure out what stream we are supposed to write to...
  std::ostream *Out = &std::cout;  // Default to printing to stdout...
  if (OutputFilename != "") {
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      cerr << "Error opening '" << OutputFilename << "': File exists!\n"
           << "Use -f command line argument to force output\n";
      return 1;
    }
    Out = new std::ofstream(OutputFilename.c_str());

    if (!Out->good()) {
      cerr << "Error opening " << OutputFilename << "!\n";
      return 1;
    }
  }

  // Create a PassManager to hold and optimize the collection of passes we are
  // about to build...
  //
  PassManager Passes;

  // Create a new optimization pass for each one specified on the command line
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    enum Opts Opt = OptimizationList[i];
    for (unsigned j = 0; j < sizeof(OptTable)/sizeof(OptTable[0]); ++j)
      if (Opt == OptTable[j].OptID) {
        Passes.add(OptTable[j].PassCtor());
        break;
      }

    if (PrintEachXForm)
      Passes.add(new PrintModulePass(&std::cerr));
  }

  // Check that the module is well formed on completion of optimization
  Passes.add(createVerifierPass());

  // Write bytecode out to disk or cout as the last step...
  Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

  // Now that we have all of the passes ready, run them.
  if (Passes.run(M.get()) && !Quiet)
    cerr << "Program modified.\n";

  return 0;
}
<commit_msg>Includes -paths option to trace paths in the program<commit_after>//===----------------------------------------------------------------------===//
// LLVM 'OPT' UTILITY
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Transforms/UnifyMethodExitNodes.h"
#include "llvm/Transforms/ConstantMerge.h"
#include "llvm/Transforms/CleanupGCCOutput.h"
#include "llvm/Transforms/LevelChange.h"
#include "llvm/Transforms/MethodInlining.h"
#include "llvm/Transforms/SymbolStripping.h"
#include "llvm/Transforms/ChangeAllocations.h"
#include "llvm/Transforms/IPO/SimpleStructMutation.h"
#include "llvm/Transforms/IPO/GlobalDCE.h"
#include "llvm/Transforms/Scalar/DCE.h"
#include "llvm/Transforms/Scalar/ConstantProp.h"
#include "llvm/Transforms/Scalar/IndVarSimplify.h"
#include "llvm/Transforms/Scalar/InstructionCombining.h"
#include "llvm/Transforms/Scalar/PromoteMemoryToRegister.h"
#include "llvm/Transforms/Instrumentation/TraceValues.h"
#include "llvm/Transforms/Instrumentation/ProfilePaths.h"
#include "Support/CommandLine.h"
#include <fstream>
#include <memory>

// Opts enum - All of the transformations we can do...
enum Opts {
  // Basic optimizations
  dce, constprop, inlining, constmerge, strip, mstrip, mergereturn,

  // Miscellaneous Transformations
  raiseallocs, cleangcc,

  // Printing and verifying...
  print, verify,

  // More powerful optimizations
  indvars, instcombine, sccp, adce, raise, mem2reg,

  // Instrumentation
  trace, tracem, paths,

  // Interprocedural optimizations...
  globaldce, swapstructs, sortstructs,
};

// New template functions - Provide functions that return passes of specified
// types, with specified arguments...
//
template<class PassClass>
Pass *New() {
  return new PassClass();
}

template<class PassClass, typename ArgTy1, ArgTy1 Arg1>
Pass *New() {
  return new PassClass(Arg1);
}

template<class PassClass, typename ArgTy1, ArgTy1 Arg1,
                          typename ArgTy2, ArgTy1 Arg2>
Pass *New() {
  return new PassClass(Arg1, Arg2);
}

static Pass *NewPrintMethodPass() {
  return new PrintMethodPass("Current Method: \n", &cerr);
}

// OptTable - Correlate enum Opts to Pass constructors...
//
struct {
  enum Opts OptID;
  Pass * (*PassCtor)();
} OptTable[] = {
  { dce        , New<DeadCodeElimination> },
  { constprop  , New<ConstantPropogation> },
  { inlining   , New<MethodInlining> },
  { constmerge , New<ConstantMerge> },
  { strip      , New<SymbolStripping> },
  { mstrip     , New<FullSymbolStripping> },
  { mergereturn, New<UnifyMethodExitNodes> },

  { indvars    , New<InductionVariableSimplify> },
  { instcombine, New<InstructionCombining> },
  { sccp       , New<SCCPPass> },
  { adce       , New<AgressiveDCE> },
  { raise      , New<RaisePointerReferences> },
  { mem2reg    , newPromoteMemoryToRegister },

  { trace      , New<InsertTraceCode, bool, true, bool, true> },
  { tracem     , New<InsertTraceCode, bool, false, bool, true> },
  { paths      , New<ProfilePaths> },
  { print      , NewPrintMethodPass },
  { verify     , createVerifierPass },
  { raiseallocs, New<RaiseAllocations> },
  { cleangcc   , New<CleanupGCCOutput> },
  { globaldce  , New<GlobalDCE> },
  { swapstructs, New<SimpleStructMutation, SimpleStructMutation::Transform,
                     SimpleStructMutation::SwapElements>},
  { sortstructs, New<SimpleStructMutation, SimpleStructMutation::Transform,
                     SimpleStructMutation::SortElements>},
};

// Command line option handling code...
//
cl::String InputFilename ("", "Load <arg> file to optimize", cl::NoFlags, "-");
cl::String OutputFilename("o", "Override output filename", cl::NoFlags, "");
cl::Flag   Force         ("f", "Overwrite output files", cl::NoFlags, false);
cl::Flag   PrintEachXForm("p", "Print module after each transformation");
cl::Flag   Quiet         ("q", "Don't print modifying pass names", 0, false);
cl::Alias  QuietA        ("quiet", "Alias for -q", cl::NoFlags, Quiet);
cl::EnumList<enum Opts> OptimizationList(cl::NoFlags,
  clEnumVal(dce        , "Dead Code Elimination"),
  clEnumVal(constprop  , "Simple constant propogation"),
 clEnumValN(inlining   , "inline", "Method integration"),
  clEnumVal(constmerge , "Merge identical global constants"),
  clEnumVal(strip      , "Strip symbols"),
  clEnumVal(mstrip     , "Strip module symbols"),
  clEnumVal(mergereturn, "Unify method exit nodes"),

  clEnumVal(indvars    , "Simplify Induction Variables"),
  clEnumVal(instcombine, "Combine redundant instructions"),
  clEnumVal(sccp       , "Sparse Conditional Constant Propogation"),
  clEnumVal(adce       , "Agressive DCE"),
  clEnumVal(mem2reg    , "Promote alloca locations to registers"),

  clEnumVal(globaldce  , "Remove unreachable globals"),
  clEnumVal(swapstructs, "Swap structure types around"),
  clEnumVal(sortstructs, "Sort structure elements"),

  clEnumVal(raiseallocs, "Raise allocations from calls to instructions"),
  clEnumVal(cleangcc   , "Cleanup GCC Output"),
  clEnumVal(raise      , "Raise to Higher Level"),
  clEnumVal(trace      , "Insert BB & Method trace code"),
  clEnumVal(tracem     , "Insert Method trace code only"),
  clEnumVal(paths      , "Insert path profiling instrumentation"),
  clEnumVal(print      , "Print working method to stderr"),
  clEnumVal(verify     , "Verify module is well formed"),
0);

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");

  // Load the input module...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
  if (M.get() == 0) {
    cerr << "bytecode didn't read correctly.\n";
    return 1;
  }

  // Figure out what stream we are supposed to write to...
  std::ostream *Out = &std::cout;  // Default to printing to stdout...
  if (OutputFilename != "") {
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      cerr << "Error opening '" << OutputFilename << "': File exists!\n"
           << "Use -f command line argument to force output\n";
      return 1;
    }
    Out = new std::ofstream(OutputFilename.c_str());

    if (!Out->good()) {
      cerr << "Error opening " << OutputFilename << "!\n";
      return 1;
    }
  }

  // Create a PassManager to hold and optimize the collection of passes we are
  // about to build...
  //
  PassManager Passes;

  // Create a new optimization pass for each one specified on the command line
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    enum Opts Opt = OptimizationList[i];
    for (unsigned j = 0; j < sizeof(OptTable)/sizeof(OptTable[0]); ++j)
      if (Opt == OptTable[j].OptID) {
        Passes.add(OptTable[j].PassCtor());
        break;
      }

    if (PrintEachXForm)
      Passes.add(new PrintModulePass(&std::cerr));
  }

  // Check that the module is well formed on completion of optimization
  Passes.add(createVerifierPass());

  // Write bytecode out to disk or cout as the last step...
  Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

  // Now that we have all of the passes ready, run them.
  if (Passes.run(M.get()) && !Quiet)
    cerr << "Program modified.\n";

  return 0;
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
// LLVM 'OPT' UTILITY
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/Writer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Optimizations/AllOpts.h"
#include "llvm/Transforms/Instrumentation/TraceValues.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Transforms/ConstantMerge.h"
#include <fstream>

using namespace opt;

enum Opts {
  // Basic optimizations
  dce, constprop, inlining, mergecons, strip, mstrip,

  // Miscellaneous Transformations
  trace, tracem, print,

  // More powerful optimizations
  indvars, sccp, adce, raise,
};

struct {
  enum Opts OptID;
  Pass *ThePass;
} OptTable[] = {
  { dce      , new opt::DeadCodeElimination() },
  { constprop, new opt::ConstantPropogation() },
  { inlining , new opt::MethodInlining() },
  { mergecons, new ConstantMerge() },
  { strip    , new opt::SymbolStripping() },
  { mstrip   , new opt::FullSymbolStripping() },
  { indvars  , new opt::InductionVariableCannonicalize() },
  { sccp     , new opt::SCCPPass() },
  { adce     , new opt::AgressiveDCE() },
  { raise    , new opt::RaiseRepresentation() },
  { trace    , new InsertTraceCode(true, true) },
  { tracem   , new InsertTraceCode(false, true) },
  { print    , new PrintModulePass("Current Method: \n",&cerr) },
};

cl::String InputFilename ("", "Load <arg> file to optimize", cl::NoFlags, "-");
cl::String OutputFilename("o", "Override output filename", cl::NoFlags, "");
cl::Flag   Force         ("f", "Overwrite output files", cl::NoFlags, false);
cl::Flag   Quiet         ("q", "Don't print modifying pass names", 0, false);
cl::Alias  QuietA        ("quiet", "Alias for -q", cl::NoFlags, Quiet);
cl::EnumList<enum Opts> OptimizationList(cl::NoFlags,
  clEnumVal(dce      , "Dead Code Elimination"),
  clEnumVal(constprop, "Simple Constant Propogation"),
 clEnumValN(inlining , "inline", "Method Integration"),
  clEnumVal(mergecons, "Merge identical global constants"),
  clEnumVal(strip    , "Strip Symbols"),
  clEnumVal(mstrip   , "Strip Module Symbols"),
  clEnumVal(indvars  , "Simplify Induction Variables"),
  clEnumVal(sccp     , "Sparse Conditional Constant Propogation"),
  clEnumVal(adce     , "Agressive DCE"),
  clEnumVal(raise    , "Raise to Higher Level"),
  clEnumVal(trace    , "Insert BB & Method trace code"),
  clEnumVal(tracem   , "Insert Method trace code only"),
  clEnumVal(print    , "Print working method to stderr"),
0);

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");

  Module *C = ParseBytecodeFile(InputFilename);
  if (C == 0) {
    cerr << "bytecode didn't read correctly.\n";
    return 1;
  }

  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    enum Opts Opt = OptimizationList[i];

    unsigned j;
    for (j = 0; j < sizeof(OptTable)/sizeof(OptTable[0]); ++j) {
      if (Opt == OptTable[j].OptID) {
        if (OptTable[j].ThePass->run(C) && !Quiet)
          cerr << OptimizationList.getArgName(Opt)
	       << " pass made modifications!\n";
        break;
      }
    }

    if (j == sizeof(OptTable)/sizeof(OptTable[0]))
      cerr << "Optimization tables inconsistent!!\n";
  }

  ostream *Out = &cout;  // Default to printing to stdout...
  if (OutputFilename != "") {
    Out = new ofstream(OutputFilename.c_str(),
                       (Force ? 0 : ios::noreplace)|ios::out);
    if (!Out->good()) {
      cerr << "Error opening " << OutputFilename << "!\n";
      delete C;
      return 1;
    }
  }

  // Okay, we're done now... write out result...
  WriteBytecodeToFile(C, *Out);
  delete C;

  if (Out != &cout) delete Out;
  return 0;
}
<commit_msg>Add hook for GCC cleanup pass<commit_after>//===----------------------------------------------------------------------===//
// LLVM 'OPT' UTILITY
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/Writer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Optimizations/AllOpts.h"
#include "llvm/Transforms/Instrumentation/TraceValues.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Transforms/ConstantMerge.h"
#include "llvm/Transforms/CleanupGCCOutput.h"
#include <fstream>

using namespace opt;

enum Opts {
  // Basic optimizations
  dce, constprop, inlining, mergecons, strip, mstrip,

  // Miscellaneous Transformations
  trace, tracem, print, cleangcc,

  // More powerful optimizations
  indvars, sccp, adce, raise,
};

struct {
  enum Opts OptID;
  Pass *ThePass;
} OptTable[] = {
  { dce      , new opt::DeadCodeElimination() },
  { constprop, new opt::ConstantPropogation() },
  { inlining , new opt::MethodInlining() },
  { mergecons, new ConstantMerge() },
  { strip    , new opt::SymbolStripping() },
  { mstrip   , new opt::FullSymbolStripping() },
  { indvars  , new opt::InductionVariableCannonicalize() },
  { sccp     , new opt::SCCPPass() },
  { adce     , new opt::AgressiveDCE() },
  { raise    , new opt::RaiseRepresentation() },
  { trace    , new InsertTraceCode(true, true) },
  { tracem   , new InsertTraceCode(false, true) },
  { print    , new PrintModulePass("Current Method: \n",&cerr) },
  { cleangcc , new CleanupGCCOutput() },
};

cl::String InputFilename ("", "Load <arg> file to optimize", cl::NoFlags, "-");
cl::String OutputFilename("o", "Override output filename", cl::NoFlags, "");
cl::Flag   Force         ("f", "Overwrite output files", cl::NoFlags, false);
cl::Flag   Quiet         ("q", "Don't print modifying pass names", 0, false);
cl::Alias  QuietA        ("quiet", "Alias for -q", cl::NoFlags, Quiet);
cl::EnumList<enum Opts> OptimizationList(cl::NoFlags,
  clEnumVal(dce      , "Dead Code Elimination"),
  clEnumVal(constprop, "Simple Constant Propogation"),
 clEnumValN(inlining , "inline", "Method Integration"),
  clEnumVal(mergecons, "Merge identical global constants"),
  clEnumVal(strip    , "Strip Symbols"),
  clEnumVal(mstrip   , "Strip Module Symbols"),
  clEnumVal(indvars  , "Simplify Induction Variables"),
  clEnumVal(sccp     , "Sparse Conditional Constant Propogation"),
  clEnumVal(adce     , "Agressive DCE"),
  clEnumVal(cleangcc , "Cleanup GCC Output"),
  clEnumVal(raise    , "Raise to Higher Level"),
  clEnumVal(trace    , "Insert BB & Method trace code"),
  clEnumVal(tracem   , "Insert Method trace code only"),
  clEnumVal(print    , "Print working method to stderr"),
0);

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");

  Module *C = ParseBytecodeFile(InputFilename);
  if (C == 0) {
    cerr << "bytecode didn't read correctly.\n";
    return 1;
  }

  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    enum Opts Opt = OptimizationList[i];

    unsigned j;
    for (j = 0; j < sizeof(OptTable)/sizeof(OptTable[0]); ++j) {
      if (Opt == OptTable[j].OptID) {
        if (OptTable[j].ThePass->run(C) && !Quiet)
          cerr << OptimizationList.getArgName(Opt)
	       << " pass made modifications!\n";
        break;
      }
    }

    if (j == sizeof(OptTable)/sizeof(OptTable[0]))
      cerr << "Optimization tables inconsistent!!\n";
  }

  ostream *Out = &cout;  // Default to printing to stdout...
  if (OutputFilename != "") {
    Out = new ofstream(OutputFilename.c_str(),
                       (Force ? 0 : ios::noreplace)|ios::out);
    if (!Out->good()) {
      cerr << "Error opening " << OutputFilename << "!\n";
      delete C;
      return 1;
    }
  }

  // Okay, we're done now... write out result...
  WriteBytecodeToFile(C, *Out);
  delete C;

  if (Out != &cout) delete Out;
  return 0;
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
// LLVM 'OPT' UTILITY
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Transforms/UnifyMethodExitNodes.h"
#include "llvm/Transforms/ConstantMerge.h"
#include "llvm/Transforms/CleanupGCCOutput.h"
#include "llvm/Transforms/LevelChange.h"
#include "llvm/Transforms/MethodInlining.h"
#include "llvm/Transforms/SymbolStripping.h"
#include "llvm/Transforms/ChangeAllocations.h"
#include "llvm/Transforms/IPO/SimpleStructMutation.h"
#include "llvm/Transforms/IPO/GlobalDCE.h"
#include "llvm/Transforms/Scalar/DCE.h"
#include "llvm/Transforms/Scalar/ConstantProp.h"
#include "llvm/Transforms/Scalar/IndVarSimplify.h"
#include "llvm/Transforms/Scalar/InstructionCombining.h"
#include "llvm/Transforms/Scalar/PromoteMemoryToRegister.h"
#include "llvm/Transforms/Instrumentation/TraceValues.h"
#include "llvm/Transforms/Instrumentation/ProfilePaths.h"
#include "Support/CommandLine.h"
#include <fstream>
#include <memory>

// Opts enum - All of the transformations we can do...
enum Opts {
  // Basic optimizations
  dce, constprop, inlining, constmerge, strip, mstrip, mergereturn,

  // Miscellaneous Transformations
  raiseallocs, cleangcc,

  // Printing and verifying...
  print, verify,

  // More powerful optimizations
  indvars, instcombine, sccp, adce, raise, mem2reg,

  // Instrumentation
  trace, tracem, paths,

  // Interprocedural optimizations...
  globaldce, swapstructs, sortstructs,
};

static Pass *createPrintMethodPass() {
  return new PrintMethodPass("Current Method: \n", &cerr);
}

// OptTable - Correlate enum Opts to Pass constructors...
//
struct {
  enum Opts OptID;
  Pass * (*PassCtor)();
} OptTable[] = {
  { dce        , createDeadCodeEliminationPass },
  { constprop  , createConstantPropogationPass },
  { inlining   , createMethodInliningPass },
  { constmerge , createConstantMergePass },
  { strip      , createSymbolStrippingPass },
  { mstrip     , createFullSymbolStrippingPass },
  { mergereturn, createUnifyMethodExitNodesPass },

  { indvars    , createIndVarSimplifyPass },
  { instcombine, createInstructionCombiningPass },
  { sccp       , createSCCPPass },
  { adce       , createAgressiveDCEPass },
  { raise      , createRaisePointerReferencesPass },
  { mem2reg    , newPromoteMemoryToRegister },

  { trace      , createTraceValuesPassForBasicBlocks },
  { tracem     , createTraceValuesPassForMethod },
  { paths      , createProfilePathsPass },

  { print      , createPrintMethodPass },
  { verify     , createVerifierPass },

  { raiseallocs, createRaiseAllocationsPass },
  { cleangcc   , createCleanupGCCOutputPass },
  { globaldce  , createGlobalDCEPass },
  { swapstructs, createSwapElementsPass },
  { sortstructs, createSortElementsPass },
};

// Command line option handling code...
//
cl::String InputFilename ("", "Load <arg> file to optimize", cl::NoFlags, "-");
cl::String OutputFilename("o", "Override output filename", cl::NoFlags, "");
cl::Flag   Force         ("f", "Overwrite output files", cl::NoFlags, false);
cl::Flag   PrintEachXForm("p", "Print module after each transformation");
cl::Flag   Quiet         ("q", "Don't print modifying pass names", 0, false);
cl::Alias  QuietA        ("quiet", "Alias for -q", cl::NoFlags, Quiet);
cl::EnumList<enum Opts> OptimizationList(cl::NoFlags,
  clEnumVal(dce        , "Dead Code Elimination"),
  clEnumVal(constprop  , "Simple constant propogation"),
 clEnumValN(inlining   , "inline", "Method integration"),
  clEnumVal(constmerge , "Merge identical global constants"),
  clEnumVal(strip      , "Strip symbols"),
  clEnumVal(mstrip     , "Strip module symbols"),
  clEnumVal(mergereturn, "Unify method exit nodes"),

  clEnumVal(indvars    , "Simplify Induction Variables"),
  clEnumVal(instcombine, "Combine redundant instructions"),
  clEnumVal(sccp       , "Sparse Conditional Constant Propogation"),
  clEnumVal(adce       , "Agressive DCE"),
  clEnumVal(mem2reg    , "Promote alloca locations to registers"),

  clEnumVal(globaldce  , "Remove unreachable globals"),
  clEnumVal(swapstructs, "Swap structure types around"),
  clEnumVal(sortstructs, "Sort structure elements"),

  clEnumVal(raiseallocs, "Raise allocations from calls to instructions"),
  clEnumVal(cleangcc   , "Cleanup GCC Output"),
  clEnumVal(raise      , "Raise to Higher Level"),
  clEnumVal(trace      , "Insert BB & Method trace code"),
  clEnumVal(tracem     , "Insert Method trace code only"),
  clEnumVal(paths      , "Insert path profiling instrumentation"),
  clEnumVal(print      , "Print working method to stderr"),
  clEnumVal(verify     , "Verify module is well formed"),
0);

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");

  // Load the input module...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
  if (M.get() == 0) {
    cerr << "bytecode didn't read correctly.\n";
    return 1;
  }

  // Figure out what stream we are supposed to write to...
  std::ostream *Out = &std::cout;  // Default to printing to stdout...
  if (OutputFilename != "") {
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      cerr << "Error opening '" << OutputFilename << "': File exists!\n"
           << "Use -f command line argument to force output\n";
      return 1;
    }
    Out = new std::ofstream(OutputFilename.c_str());

    if (!Out->good()) {
      cerr << "Error opening " << OutputFilename << "!\n";
      return 1;
    }
  }

  // Create a PassManager to hold and optimize the collection of passes we are
  // about to build...
  //
  PassManager Passes;

  // Create a new optimization pass for each one specified on the command line
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    enum Opts Opt = OptimizationList[i];
    for (unsigned j = 0; j < sizeof(OptTable)/sizeof(OptTable[0]); ++j)
      if (Opt == OptTable[j].OptID) {
        Passes.add(OptTable[j].PassCtor());
        break;
      }

    if (PrintEachXForm)
      Passes.add(new PrintModulePass(&std::cerr));
  }

  // Check that the module is well formed on completion of optimization
  Passes.add(createVerifierPass());

  // Write bytecode out to disk or cout as the last step...
  Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

  // Now that we have all of the passes ready, run them.
  if (Passes.run(M.get()) && !Quiet)
    cerr << "Program modified.\n";

  return 0;
}
<commit_msg>Expose dead instruction elimination pass<commit_after>//===----------------------------------------------------------------------===//
// LLVM 'OPT' UTILITY
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Transforms/UnifyMethodExitNodes.h"
#include "llvm/Transforms/ConstantMerge.h"
#include "llvm/Transforms/CleanupGCCOutput.h"
#include "llvm/Transforms/LevelChange.h"
#include "llvm/Transforms/MethodInlining.h"
#include "llvm/Transforms/SymbolStripping.h"
#include "llvm/Transforms/ChangeAllocations.h"
#include "llvm/Transforms/IPO/SimpleStructMutation.h"
#include "llvm/Transforms/IPO/GlobalDCE.h"
#include "llvm/Transforms/Scalar/DCE.h"
#include "llvm/Transforms/Scalar/ConstantProp.h"
#include "llvm/Transforms/Scalar/IndVarSimplify.h"
#include "llvm/Transforms/Scalar/InstructionCombining.h"
#include "llvm/Transforms/Scalar/PromoteMemoryToRegister.h"
#include "llvm/Transforms/Instrumentation/TraceValues.h"
#include "llvm/Transforms/Instrumentation/ProfilePaths.h"
#include "Support/CommandLine.h"
#include <fstream>
#include <memory>

// Opts enum - All of the transformations we can do...
enum Opts {
  // Basic optimizations
  dce, die, constprop, inlining, constmerge, strip, mstrip, mergereturn,

  // Miscellaneous Transformations
  raiseallocs, cleangcc,

  // Printing and verifying...
  print, verify,

  // More powerful optimizations
  indvars, instcombine, sccp, adce, raise, mem2reg,

  // Instrumentation
  trace, tracem, paths,

  // Interprocedural optimizations...
  globaldce, swapstructs, sortstructs,
};

static Pass *createPrintMethodPass() {
  return new PrintMethodPass("Current Method: \n", &cerr);
}

// OptTable - Correlate enum Opts to Pass constructors...
//
struct {
  enum Opts OptID;
  Pass * (*PassCtor)();
} OptTable[] = {
  { dce        , createDeadCodeEliminationPass },
  { die        , createDeadInstEliminationPass },
  { constprop  , createConstantPropogationPass },
  { inlining   , createMethodInliningPass },
  { constmerge , createConstantMergePass },
  { strip      , createSymbolStrippingPass },
  { mstrip     , createFullSymbolStrippingPass },
  { mergereturn, createUnifyMethodExitNodesPass },

  { indvars    , createIndVarSimplifyPass },
  { instcombine, createInstructionCombiningPass },
  { sccp       , createSCCPPass },
  { adce       , createAgressiveDCEPass },
  { raise      , createRaisePointerReferencesPass },
  { mem2reg    , newPromoteMemoryToRegister },

  { trace      , createTraceValuesPassForBasicBlocks },
  { tracem     , createTraceValuesPassForMethod },
  { paths      , createProfilePathsPass },

  { print      , createPrintMethodPass },
  { verify     , createVerifierPass },

  { raiseallocs, createRaiseAllocationsPass },
  { cleangcc   , createCleanupGCCOutputPass },
  { globaldce  , createGlobalDCEPass },
  { swapstructs, createSwapElementsPass },
  { sortstructs, createSortElementsPass },
};

// Command line option handling code...
//
cl::String InputFilename ("", "Load <arg> file to optimize", cl::NoFlags, "-");
cl::String OutputFilename("o", "Override output filename", cl::NoFlags, "");
cl::Flag   Force         ("f", "Overwrite output files", cl::NoFlags, false);
cl::Flag   PrintEachXForm("p", "Print module after each transformation");
cl::Flag   Quiet         ("q", "Don't print modifying pass names", 0, false);
cl::Alias  QuietA        ("quiet", "Alias for -q", cl::NoFlags, Quiet);
cl::EnumList<enum Opts> OptimizationList(cl::NoFlags,
  clEnumVal(dce        , "Dead Code Elimination"),
  clEnumVal(die        , "Dead Instruction Elimination"),
  clEnumVal(constprop  , "Simple constant propogation"),
 clEnumValN(inlining   , "inline", "Method integration"),
  clEnumVal(constmerge , "Merge identical global constants"),
  clEnumVal(strip      , "Strip symbols"),
  clEnumVal(mstrip     , "Strip module symbols"),
  clEnumVal(mergereturn, "Unify method exit nodes"),

  clEnumVal(indvars    , "Simplify Induction Variables"),
  clEnumVal(instcombine, "Combine redundant instructions"),
  clEnumVal(sccp       , "Sparse Conditional Constant Propogation"),
  clEnumVal(adce       , "Agressive DCE"),
  clEnumVal(mem2reg    , "Promote alloca locations to registers"),

  clEnumVal(globaldce  , "Remove unreachable globals"),
  clEnumVal(swapstructs, "Swap structure types around"),
  clEnumVal(sortstructs, "Sort structure elements"),

  clEnumVal(raiseallocs, "Raise allocations from calls to instructions"),
  clEnumVal(cleangcc   , "Cleanup GCC Output"),
  clEnumVal(raise      , "Raise to Higher Level"),
  clEnumVal(trace      , "Insert BB & Method trace code"),
  clEnumVal(tracem     , "Insert Method trace code only"),
  clEnumVal(paths      , "Insert path profiling instrumentation"),
  clEnumVal(print      , "Print working method to stderr"),
  clEnumVal(verify     , "Verify module is well formed"),
0);

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");

  // Load the input module...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
  if (M.get() == 0) {
    cerr << "bytecode didn't read correctly.\n";
    return 1;
  }

  // Figure out what stream we are supposed to write to...
  std::ostream *Out = &std::cout;  // Default to printing to stdout...
  if (OutputFilename != "") {
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      cerr << "Error opening '" << OutputFilename << "': File exists!\n"
           << "Use -f command line argument to force output\n";
      return 1;
    }
    Out = new std::ofstream(OutputFilename.c_str());

    if (!Out->good()) {
      cerr << "Error opening " << OutputFilename << "!\n";
      return 1;
    }
  }

  // Create a PassManager to hold and optimize the collection of passes we are
  // about to build...
  //
  PassManager Passes;

  // Create a new optimization pass for each one specified on the command line
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    enum Opts Opt = OptimizationList[i];
    for (unsigned j = 0; j < sizeof(OptTable)/sizeof(OptTable[0]); ++j)
      if (Opt == OptTable[j].OptID) {
        Passes.add(OptTable[j].PassCtor());
        break;
      }

    if (PrintEachXForm)
      Passes.add(new PrintModulePass(&std::cerr));
  }

  // Check that the module is well formed on completion of optimization
  Passes.add(createVerifierPass());

  // Write bytecode out to disk or cout as the last step...
  Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

  // Now that we have all of the passes ready, run them.
  if (Passes.run(M.get()) && !Quiet)
    cerr << "Program modified.\n";

  return 0;
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2003-2005 Max Howell <max.howell@methylblue.com>
    Copyright (c) 2007-2009 Mark Kretschmann <kretschmann@kde.org>
    Copyright (c) 2010 Kevin Funk <krf@electrostorm.net>
    Copyright (c) 2011 Harald Sitter <sitter@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "debug.h"
#include "debug_p.h"

#include <QtCore/QMutex>
#include <QtCore/QObject>
#include <QtGui/QApplication>

#include <iostream>b
#include <unistd.h>

// Define Application wide prefix
#ifndef APP_PREFIX
#define APP_PREFIX QLatin1String( "PHONON-GST" )
#endif

#define DEBUG_INDENT_OBJECTNAME QLatin1String("Debug_Indent_object")

QMutex Debug::mutex( QMutex::Recursive );

using namespace Debug;

static bool s_debugEnabled = true;
static bool s_debugColorsEnabled = true;

IndentPrivate::IndentPrivate(QObject* parent)
    : QObject(parent)
{
    setObjectName( DEBUG_INDENT_OBJECTNAME );
}

/**
 * We can't use a statically instantiated QString for the indent, because
 * static namespaces are unique to each dlopened library. So we piggy back
 * the QString on the KApplication instance
 */
IndentPrivate* IndentPrivate::instance()
{
    QObject* qOApp = reinterpret_cast<QObject*>(qApp);
    QObject* obj = qOApp ? qOApp->findChild<QObject*>( DEBUG_INDENT_OBJECTNAME ) : 0;
    return (obj ? static_cast<IndentPrivate*>( obj ) : new IndentPrivate( qApp ));
}

/*
  Text color codes (use last digit here)
  30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
*/
static int s_colors[] = { 1, 2, 4, 5, 6 }; // no yellow and white for sanity
static int s_colorIndex = 0;

static QString toString( DebugLevel level )
{
    switch( level )
    {
        case KDEBUG_WARN:
            return "[WARNING]";
        case KDEBUG_ERROR:
            return "[ERROR__]";
        case KDEBUG_FATAL:
            return "[FATAL__]";
        default:
            return QString();
    }
}

static int toColor( DebugLevel level )
{
    switch( level ) {
        case KDEBUG_WARN:
            return 3; // red
        case KDEBUG_ERROR:
        case KDEBUG_FATAL:
            return 1; // yellow
        default:
            return 0; // default: black
    }
}

static QString colorize( const QString &text, int color = s_colorIndex )
{
    if( !debugColorEnabled() )
        return text;

    return QString( "\x1b[00;3%1m%2\x1b[00;39m" ).arg( QString::number(s_colors[color]), text );
}

static QString reverseColorize( const QString &text, int color )
{
    if( !debugColorEnabled() )
        return text;

    return QString( "\x1b[07;3%1m%2\x1b[00;39m" ).arg( QString::number(color), text );
}

QString Debug::indent()
{
    return IndentPrivate::instance()->m_string;
}

bool Debug::debugEnabled()
{
    return s_debugEnabled;
}

bool Debug::debugColorEnabled()
{
    return s_debugColorsEnabled;
}

void Debug::setDebugEnabled( bool enable )
{
    s_debugEnabled = enable;
}

void Debug::setColoredDebug( bool enable )
{
    s_debugColorsEnabled = enable;
}

QDebug Debug::dbgstream( DebugLevel level )
{
#ifdef __GNUC__
#warning FIXME
#endif
//    if( !debugEnabled() )
//        return kDebugDevNull();

    mutex.lock();
    const QString currentIndent = indent();
    mutex.unlock();

    QString text = QString("%1%2").arg( APP_PREFIX ).arg( currentIndent );
    if ( level > KDEBUG_INFO )
        text.append( ' ' + reverseColorize( toString(level), toColor( level ) ) );

    return QDebug( QtDebugMsg ) << qPrintable( text );
}

void Debug::perfLog( const QString &message, const QString &func )
{
#ifdef Q_OS_UNIX
    if( !debugEnabled() )
        return;

    QString str = QString( "MARK: %1: %2 %3" ).arg( qApp->applicationName(), func, message );
    access( str.toLocal8Bit().data(), F_OK );
#endif
}

Block::Block( const char *label )
    : m_label( label )
    , m_color( s_colorIndex )
{
    if( !debugEnabled() )
        return;

#if QT_VERSION >= 0x040700
    m_startTime.start();
#else
    m_startTime = QTime::currentTime();
#endif

    mutex.lock();
    s_colorIndex = (s_colorIndex + 1) % 5;
    dbgstream()
        << qPrintable( colorize( QLatin1String( "BEGIN:" ), m_color ) )
        << m_label;
    IndentPrivate::instance()->m_string += QLatin1String("  ");
    mutex.unlock();
}

Block::~Block()
{
    if( !debugEnabled() )
        return;

#if QT_VERSION >= 0x040700
    const double duration = m_startTime.elapsed() / 1000.0;
#else
    const double duration = (double)m_startTime.msecsTo( QTime::currentTime() ) / 1000.0;
#endif

    mutex.lock();
    IndentPrivate::instance()->m_string.truncate( Debug::indent().length() - 2 );
    mutex.unlock();

    // Print timing information, and a special message (DELAY) if the method took longer than 5s
    if( duration < 5.0 )
    {
        dbgstream()
            << qPrintable( colorize( QLatin1String( "END__:" ), m_color ) )
            << m_label
            << qPrintable( colorize( QString( "[Took: %3s]")
                                     .arg( QString::number(duration, 'g', 2) ), m_color ) );
    }
    else
    {
        dbgstream()
            << qPrintable( colorize( QString( "END__:" ), m_color ) )
            << m_label
            << qPrintable( reverseColorize( QString( "[DELAY Took (quite long) %3s]")
                                            .arg( QString::number(duration, 'g', 2) ), toColor( KDEBUG_WARN ) ) );
    }
}

void Debug::stamp()
{
    static int n = 0;
    debug() << "| Stamp: " << ++n << endl;
}
<commit_msg>warning--<commit_after>/*
    Copyright (c) 2003-2005 Max Howell <max.howell@methylblue.com>
    Copyright (c) 2007-2009 Mark Kretschmann <kretschmann@kde.org>
    Copyright (c) 2010 Kevin Funk <krf@electrostorm.net>
    Copyright (c) 2011 Harald Sitter <sitter@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "debug.h"
#include "debug_p.h"

#include <QtCore/QMutex>
#include <QtCore/QObject>
#include <QtGui/QApplication>

#include <iostream>
#include <unistd.h>

// Define Application wide prefix
#ifndef APP_PREFIX
#define APP_PREFIX QLatin1String( "PHONON-GST" )
#endif

#define DEBUG_INDENT_OBJECTNAME QLatin1String("Debug_Indent_object")

QMutex Debug::mutex( QMutex::Recursive );

using namespace Debug;

static bool s_debugEnabled = true;
static bool s_debugColorsEnabled = true;

IndentPrivate::IndentPrivate(QObject* parent)
    : QObject(parent)
{
    setObjectName( DEBUG_INDENT_OBJECTNAME );
}

/**
 * We can't use a statically instantiated QString for the indent, because
 * static namespaces are unique to each dlopened library. So we piggy back
 * the QString on the KApplication instance
 */
IndentPrivate* IndentPrivate::instance()
{
    QObject* qOApp = reinterpret_cast<QObject*>(qApp);
    QObject* obj = qOApp ? qOApp->findChild<QObject*>( DEBUG_INDENT_OBJECTNAME ) : 0;
    return (obj ? static_cast<IndentPrivate*>( obj ) : new IndentPrivate( qApp ));
}

/*
  Text color codes (use last digit here)
  30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
*/
static int s_colors[] = { 1, 2, 4, 5, 6 }; // no yellow and white for sanity
static int s_colorIndex = 0;

static QString toString( DebugLevel level )
{
    switch( level )
    {
        case KDEBUG_WARN:
            return "[WARNING]";
        case KDEBUG_ERROR:
            return "[ERROR__]";
        case KDEBUG_FATAL:
            return "[FATAL__]";
        default:
            return QString();
    }
}

static int toColor( DebugLevel level )
{
    switch( level ) {
        case KDEBUG_WARN:
            return 3; // red
        case KDEBUG_ERROR:
        case KDEBUG_FATAL:
            return 1; // yellow
        default:
            return 0; // default: black
    }
}

static QString colorize( const QString &text, int color = s_colorIndex )
{
    if( !debugColorEnabled() )
        return text;

    return QString( "\x1b[00;3%1m%2\x1b[00;39m" ).arg( QString::number(s_colors[color]), text );
}

static QString reverseColorize( const QString &text, int color )
{
    if( !debugColorEnabled() )
        return text;

    return QString( "\x1b[07;3%1m%2\x1b[00;39m" ).arg( QString::number(color), text );
}

QString Debug::indent()
{
    return IndentPrivate::instance()->m_string;
}

bool Debug::debugEnabled()
{
    return s_debugEnabled;
}

bool Debug::debugColorEnabled()
{
    return s_debugColorsEnabled;
}

void Debug::setDebugEnabled( bool enable )
{
    s_debugEnabled = enable;
}

void Debug::setColoredDebug( bool enable )
{
    s_debugColorsEnabled = enable;
}

QDebug Debug::dbgstream( DebugLevel level )
{
#ifdef __GNUC__
#warning FIXME
#endif
//    if( !debugEnabled() )
//        return kDebugDevNull();

    mutex.lock();
    const QString currentIndent = indent();
    mutex.unlock();

    QString text = QString("%1%2").arg( APP_PREFIX ).arg( currentIndent );
    if ( level > KDEBUG_INFO )
        text.append( ' ' + reverseColorize( toString(level), toColor( level ) ) );

    return QDebug( QtDebugMsg ) << qPrintable( text );
}

void Debug::perfLog( const QString &message, const QString &func )
{
#ifdef Q_OS_UNIX
    if( !debugEnabled() )
        return;

    QString str = QString( "MARK: %1: %2 %3" ).arg( qApp->applicationName(), func, message );
    access( str.toLocal8Bit().data(), F_OK );
#endif
}

Block::Block( const char *label )
    : m_label( label )
    , m_color( s_colorIndex )
{
    if( !debugEnabled() )
        return;

#if QT_VERSION >= 0x040700
    m_startTime.start();
#else
    m_startTime = QTime::currentTime();
#endif

    mutex.lock();
    s_colorIndex = (s_colorIndex + 1) % 5;
    dbgstream()
        << qPrintable( colorize( QLatin1String( "BEGIN:" ), m_color ) )
        << m_label;
    IndentPrivate::instance()->m_string += QLatin1String("  ");
    mutex.unlock();
}

Block::~Block()
{
    if( !debugEnabled() )
        return;

#if QT_VERSION >= 0x040700
    const double duration = m_startTime.elapsed() / 1000.0;
#else
    const double duration = (double)m_startTime.msecsTo( QTime::currentTime() ) / 1000.0;
#endif

    mutex.lock();
    IndentPrivate::instance()->m_string.truncate( Debug::indent().length() - 2 );
    mutex.unlock();

    // Print timing information, and a special message (DELAY) if the method took longer than 5s
    if( duration < 5.0 )
    {
        dbgstream()
            << qPrintable( colorize( QLatin1String( "END__:" ), m_color ) )
            << m_label
            << qPrintable( colorize( QString( "[Took: %3s]")
                                     .arg( QString::number(duration, 'g', 2) ), m_color ) );
    }
    else
    {
        dbgstream()
            << qPrintable( colorize( QString( "END__:" ), m_color ) )
            << m_label
            << qPrintable( reverseColorize( QString( "[DELAY Took (quite long) %3s]")
                                            .arg( QString::number(duration, 'g', 2) ), toColor( KDEBUG_WARN ) ) );
    }
}

void Debug::stamp()
{
    static int n = 0;
    debug() << "| Stamp: " << ++n << endl;
}
<|endoftext|>