<commit_before>#ifndef FASTPP_HPP
#define FASTPP_HPP

#include <phypp/core/typedefs.hpp>
#include <phypp/core/vec.hpp>
#include <phypp/reflex/reflex.hpp>
#include <phypp/core/error.hpp>
#include <phypp/utility/generic.hpp>
#include <phypp/utility/string.hpp>
#include <phypp/utility/time.hpp>
#include <phypp/math/base.hpp>
#include <phypp/astro/astro.hpp>
#include <phypp/io/ascii.hpp>
#include "thread_worker_pool.hpp"

using namespace phypp;

extern const char* fastpp_version;

// Program structures
// ------------------

enum class parallel_choice {
    none, sources, models
};

// Program options read from parameter file
struct options_t {
    // Input catalog parameters
    std::string catalog;
    float ab_zeropoint = 23.9;
    std::string name_zphot = "z_phot";

    // Input spectrum parameters
    std::string spectrum;
    bool auto_scale = false;

    // Filter database parameters
    std::string filters_res;
    int_t filters_format = 1;

    // Templates parameter
    std::string temp_err_file;
    std::string library_dir;
    std::string library;
    std::string resolution;
    std::string imf;
    std::string sfh;
    std::string dust_law;
    std::string my_sfh;
    float dust_noll_eb = 1.0;
    float dust_noll_delta = -0.2;

    // Grid parameters
    float log_tau_min = 6.5;
    float log_tau_max = 10.5;
    float log_tau_step = 0.5;
    float log_age_min = 6.3;
    float log_age_max = 10.3;
    float log_age_step = 0.5;
    bool no_max_age = false;
    float z_min = 0.001;
    float z_max = 9.0;
    float z_step = 0.02;
    int_t z_step_type = 0;
    float a_v_min = 0;
    float a_v_max = 3;
    float a_v_step = 0.1;
    vec1f metal;

    // Cosmology parameters
    astro::cosmo_t cosmo;

    // Output parameters
    std::string output_dir;
    std::string output_file;
    bool save_chi_grid = false;
    uint_t n_sim = 0;
    vec1f c_interval = {68.0};
    bool best_fit = false;

    // NB: parameters below were not in original FAST

    bool force_zphot = false;
    bool best_at_zphot = false;
    float zphot_conf = fnan;
    bool verbose = false;
    bool save_sim = false;
    bool best_from_sim = false;
    parallel_choice parallel = parallel_choice::none;
    uint_t n_thread = 0;
    uint_t max_queued_fits = 500;
};

// Filter passband
struct fast_filter_t {
    uint_t id = npos;
    bool spectral = false;
    vec1f wl, tr;
};

// Holds the input state of the program
struct input_state_t {
    // List of filter ID used in the photometric catalog
    vec1u no_filt;                      // [nfilt]
    // List of spectral bins ID in the spectroscopic catalog
    vec1u no_spec;                      // [nspec]
    // Central wavelength of the filters
    vec1d lambda;                       // [nfilt+nspec]

    // Photometry & parameters of all sources in the catalog
    vec1s id;                           // [ngal]
    vec1f zspec;                        // [ngal]
    vec2f zphot;                        // [ngal,1+2*nzconf]
    vec1f zphot_conf;                   // [nzconf]
    vec2f flux, eflux;                  // [ngal,nfilt+nspec]
    vec1u nobs;                         // [ngal]
    vec1f conf_interval;                // [nconf]

    // Filter database
    // NB: for reference, in FAST: filters = [4,nfilt+nspec], with 4={ID,wl,tr,type}
    // with 'type=1' for photometry and 'type=0' for spectroscopy
    vec<1,fast_filter_t> filters; // [nfilt+nspec]

    // Template error function
    vec1f tplerr_lam, tplerr_err;

    // Baked grid cache name
    std::string name;
};

// Holds the output state of the program
struct output_state_t {
    // Grid parameters
    vec1f z, metal, av, age, tau;

    // Best fits
    vec2f best_mass;                 // [ngal,1+nconf]
    vec2f best_sfr;                  // [ngal,1+nconf]
    vec2f best_ssfr;                 // [ngal,1+nconf]
    vec2f best_z;                    // [ngal,1+nconf]
    vec2f best_metal;                // [ngal,1+nconf]
    vec2f best_tau;                  // [ngal,1+nconf]
    vec2f best_age;                  // [ngal,1+nconf]
    vec2f best_av;                   // [ngal,1+nconf]
    vec1f best_chi2;                 // [ngal]
    vec1u best_model;                // [ngal]

    // Monte Carlo simulations
    vec2f mc_best_mass;              // [ngal,nsim]
    vec2f mc_best_sfr;               // [ngal,nsim]
    vec2f mc_best_chi2;              // [ngal,nsim]
    vec2u mc_best_model;             // [ngal,nsim]

    // For thread safety
    std::mutex fit_result_mutex;
};

// Structure holding the integrated fluxes of a model and associated physical parameters
struct model_t {
    vec1f flux; // [nfilt+nspec]
    float mass = 0, sfr = 0;
    uint_t im, it, ia, id, iz, igrid;
};

struct fitter_t;

// Build the grid of models and sends models to the fitter
struct gridder_t {
    const options_t& opts;
    const input_state_t& input;
    output_state_t& output;

    struct cache_manager_t {
        std::fstream cache_file;
        std::string cache_filename;

        void write_model(const model_t& model);
        bool read_model(model_t& model);
    };

    bool read_from_cache = true;
    cache_manager_t cache;

    std::array<uint_t,5> dims;
    uint_t nparam = 0;
    vec1d lum2fl;
    vec1d auniv;

    explicit gridder_t(const options_t& opts, const input_state_t& input, output_state_t& output);

    bool build_and_send(fitter_t& fitter);
    bool build_template(uint_t im, uint_t it, uint_t ia, uint_t id, uint_t iz,
        vec1f& lam, vec1f& flux, vec1f& iflux) const;
    bool build_template(uint_t igrid, vec1f& lam, vec1f& flux, vec1f& iflux) const;

    uint_t model_id(uint_t im, uint_t it, uint_t ia, uint_t id, uint_t iz) const;
    vec1u grid_ids(uint_t iflat) const;

private :
    std::string get_library_file(uint_t im, uint_t it) const;
    vec1d build_dust_law(const vec1f& lambda) const;
    vec1d build_igm_absorption(const vec1f& lambda, float z) const;
};

// Fit a model to observed fluxes
struct fitter_t {
    const options_t& opts;
    const input_state_t& input;
    const gridder_t& gridder;
    output_state_t& output;

    struct chi2_output_manager_t {
        std::fstream out_file;
        std::string out_filename;
        uint_t hpos = 0;

        // For thread safety
        std::mutex write_mutex;
    };

    bool save_chi2 = false;
    chi2_output_manager_t ochi2;

    struct model_source_pair {
        model_t model;
        uint_t i0 = 0, i1 = 0;

        model_source_pair() = default;
        explicit model_source_pair(const model_t& m, uint_t ti0, uint_t ti1) :
            model(m), i0(ti0), i1(ti1) {}
    };

    struct workers_multi_source_t {
        fitter_t& fitter;
        thread::worker_pool<model_source_pair> workers;

        explicit workers_multi_source_t(fitter_t& f);
        void process(const model_t& model);
    };

    struct workers_multi_model_t {
        fitter_t& fitter;
        thread::worker_pool<model_t> workers;

        explicit workers_multi_model_t(fitter_t& f);
        void process(const model_t& model);
    };

    std::unique_ptr<workers_multi_source_t> workers_multi_source;
    std::unique_ptr<workers_multi_model_t> workers_multi_model;

    vec2d tpl_err;         // [nz,nfilt+nspec]
    vec1u idz, idzp, idzl, idzu; // [ngal]
    vec2d sim_rnd;         // [nsim,nfilt]

    explicit fitter_t(const options_t& opts, const input_state_t& input, const gridder_t& gridder,
        output_state_t& output);

    void fit(const model_t& model);
    void find_best_fits();

private :
    inline void write_chi2(uint_t igrid, const vec1f& chi2, const vec1f& mass, const vec1f& sfr,
        uint_t i0, uint_t i1);
    inline void fit_galaxies(const model_t& model, uint_t i0, uint_t i1);
};

// Main functions
// --------------

// fast++-read_input.cpp
bool read_input(options_t& opts, input_state_t& state, const std::string& filename);

// fast++-write_output.cpp
void write_output(const options_t& opts, const input_state_t& state, const gridder_t& gridder,
    const output_state_t& output);

// Helper functions
// ----------------

namespace phypp {
namespace file {
    template<typename S, typename T>
    bool write(S& s, const T& t) {
        s.write(reinterpret_cast<const char*>(&t), sizeof(T));
        return !s.fail();
    }

    template<typename R, typename S, typename T>
    bool write_as(S& s, const T& t) {
        R r = t;
        s.write(reinterpret_cast<const char*>(&r), sizeof(R));
        return !s.fail();
    }

    template<typename S, std::size_t D, typename T>
    bool write(S& s, const vec<D,T>& t) {
        s.write(reinterpret_cast<const char*>(t.data.data()), sizeof(T)*t.size());
        return !s.fail();
    }

    template<typename S, typename T>
    bool read(S& s, T& t) {
        s.read(reinterpret_cast<char*>(&t), sizeof(T));
        return !s.fail();
    }

    template<typename R, typename S, typename T>
    bool read_as(S& s, T& t) {
        R r;
        if (s.read(reinterpret_cast<char*>(&r), sizeof(R))) {
            t = r;
        }

        return !s.fail();
    }

    template<typename S, std::size_t D, typename T>
    bool read(S& s, vec<D,T>& t) {
        s.read(reinterpret_cast<char*>(t.data.data()), sizeof(T)*t.size());
        return !s.fail();
    }
}
}

#endif
<commit_msg>Added no_cache option<commit_after>#ifndef FASTPP_HPP
#define FASTPP_HPP

#include <phypp/core/typedefs.hpp>
#include <phypp/core/vec.hpp>
#include <phypp/reflex/reflex.hpp>
#include <phypp/core/error.hpp>
#include <phypp/utility/generic.hpp>
#include <phypp/utility/string.hpp>
#include <phypp/utility/time.hpp>
#include <phypp/math/base.hpp>
#include <phypp/astro/astro.hpp>
#include <phypp/io/ascii.hpp>
#include "thread_worker_pool.hpp"

using namespace phypp;

extern const char* fastpp_version;

// Program structures
// ------------------

enum class parallel_choice {
    none, sources, models
};

// Program options read from parameter file
struct options_t {
    // Input catalog parameters
    std::string catalog;
    float ab_zeropoint = 23.9;
    std::string name_zphot = "z_phot";

    // Input spectrum parameters
    std::string spectrum;
    bool auto_scale = false;

    // Filter database parameters
    std::string filters_res;
    int_t filters_format = 1;

    // Templates parameter
    std::string temp_err_file;
    std::string library_dir;
    std::string library;
    std::string resolution;
    std::string imf;
    std::string sfh;
    std::string dust_law;
    std::string my_sfh;
    float dust_noll_eb = 1.0;
    float dust_noll_delta = -0.2;

    // Grid parameters
    float log_tau_min = 6.5;
    float log_tau_max = 10.5;
    float log_tau_step = 0.5;
    float log_age_min = 6.3;
    float log_age_max = 10.3;
    float log_age_step = 0.5;
    bool no_max_age = false;
    float z_min = 0.001;
    float z_max = 9.0;
    float z_step = 0.02;
    int_t z_step_type = 0;
    float a_v_min = 0;
    float a_v_max = 3;
    float a_v_step = 0.1;
    vec1f metal;

    // Cosmology parameters
    astro::cosmo_t cosmo;

    // Output parameters
    std::string output_dir;
    std::string output_file;
    bool save_chi_grid = false;
    uint_t n_sim = 0;
    vec1f c_interval = {68.0};
    bool best_fit = false;

    // NB: parameters below were not in original FAST

    bool force_zphot = false;
    bool best_at_zphot = false;
    float zphot_conf = fnan;
    bool verbose = false;
    bool save_sim = false;
    bool best_from_sim = false;
    bool no_cache = false;
    parallel_choice parallel = parallel_choice::none;
    uint_t n_thread = 0;
    uint_t max_queued_fits = 1000;
};

// Filter passband
struct fast_filter_t {
    uint_t id = npos;
    bool spectral = false;
    vec1f wl, tr;
};

// Holds the input state of the program
struct input_state_t {
    // List of filter ID used in the photometric catalog
    vec1u no_filt;                      // [nfilt]
    // List of spectral bins ID in the spectroscopic catalog
    vec1u no_spec;                      // [nspec]
    // Central wavelength of the filters
    vec1d lambda;                       // [nfilt+nspec]

    // Photometry & parameters of all sources in the catalog
    vec1s id;                           // [ngal]
    vec1f zspec;                        // [ngal]
    vec2f zphot;                        // [ngal,1+2*nzconf]
    vec1f zphot_conf;                   // [nzconf]
    vec2f flux, eflux;                  // [ngal,nfilt+nspec]
    vec1u nobs;                         // [ngal]
    vec1f conf_interval;                // [nconf]

    // Filter database
    // NB: for reference, in FAST: filters = [4,nfilt+nspec], with 4={ID,wl,tr,type}
    // with 'type=1' for photometry and 'type=0' for spectroscopy
    vec<1,fast_filter_t> filters; // [nfilt+nspec]

    // Template error function
    vec1f tplerr_lam, tplerr_err;

    // Baked grid cache name
    std::string name;
};

// Holds the output state of the program
struct output_state_t {
    // Grid parameters
    vec1f z, metal, av, age, tau;

    // Best fits
    vec2f best_mass;                 // [ngal,1+nconf]
    vec2f best_sfr;                  // [ngal,1+nconf]
    vec2f best_ssfr;                 // [ngal,1+nconf]
    vec2f best_z;                    // [ngal,1+nconf]
    vec2f best_metal;                // [ngal,1+nconf]
    vec2f best_tau;                  // [ngal,1+nconf]
    vec2f best_age;                  // [ngal,1+nconf]
    vec2f best_av;                   // [ngal,1+nconf]
    vec1f best_chi2;                 // [ngal]
    vec1u best_model;                // [ngal]

    // Monte Carlo simulations
    vec2f mc_best_mass;              // [ngal,nsim]
    vec2f mc_best_sfr;               // [ngal,nsim]
    vec2f mc_best_chi2;              // [ngal,nsim]
    vec2u mc_best_model;             // [ngal,nsim]

    // For thread safety
    std::mutex fit_result_mutex;
};

// Structure holding the integrated fluxes of a model and associated physical parameters
struct model_t {
    vec1f flux; // [nfilt+nspec]
    float mass = 0, sfr = 0;
    uint_t im, it, ia, id, iz, igrid;
};

struct fitter_t;

// Build the grid of models and sends models to the fitter
struct gridder_t {
    const options_t& opts;
    const input_state_t& input;
    output_state_t& output;

    struct cache_manager_t {
        std::fstream cache_file;
        std::string cache_filename;

        void write_model(const model_t& model);
        bool read_model(model_t& model);
    };

    bool read_from_cache = true;
    cache_manager_t cache;

    std::array<uint_t,5> dims;
    uint_t nparam = 0;
    vec1d lum2fl;
    vec1d auniv;

    explicit gridder_t(const options_t& opts, const input_state_t& input, output_state_t& output);

    bool build_and_send(fitter_t& fitter);
    bool build_template(uint_t im, uint_t it, uint_t ia, uint_t id, uint_t iz,
        vec1f& lam, vec1f& flux, vec1f& iflux) const;
    bool build_template(uint_t igrid, vec1f& lam, vec1f& flux, vec1f& iflux) const;

    uint_t model_id(uint_t im, uint_t it, uint_t ia, uint_t id, uint_t iz) const;
    vec1u grid_ids(uint_t iflat) const;

private :
    std::string get_library_file(uint_t im, uint_t it) const;
    vec1d build_dust_law(const vec1f& lambda) const;
    vec1d build_igm_absorption(const vec1f& lambda, float z) const;
};

// Fit a model to observed fluxes
struct fitter_t {
    const options_t& opts;
    const input_state_t& input;
    const gridder_t& gridder;
    output_state_t& output;

    struct chi2_output_manager_t {
        std::fstream out_file;
        std::string out_filename;
        uint_t hpos = 0;

        // For thread safety
        std::mutex write_mutex;
    };

    bool save_chi2 = false;
    chi2_output_manager_t ochi2;

    struct model_source_pair {
        model_t model;
        uint_t i0 = 0, i1 = 0;

        model_source_pair() = default;
        explicit model_source_pair(const model_t& m, uint_t ti0, uint_t ti1) :
            model(m), i0(ti0), i1(ti1) {}
    };

    struct workers_multi_source_t {
        fitter_t& fitter;
        thread::worker_pool<model_source_pair> workers;

        explicit workers_multi_source_t(fitter_t& f);
        void process(const model_t& model);
    };

    struct workers_multi_model_t {
        fitter_t& fitter;
        thread::worker_pool<model_t> workers;

        explicit workers_multi_model_t(fitter_t& f);
        void process(const model_t& model);
    };

    std::unique_ptr<workers_multi_source_t> workers_multi_source;
    std::unique_ptr<workers_multi_model_t> workers_multi_model;

    vec2d tpl_err;         // [nz,nfilt+nspec]
    vec1u idz, idzp, idzl, idzu; // [ngal]
    vec2d sim_rnd;         // [nsim,nfilt]

    explicit fitter_t(const options_t& opts, const input_state_t& input, const gridder_t& gridder,
        output_state_t& output);

    void fit(const model_t& model);
    void find_best_fits();

private :
    inline void write_chi2(uint_t igrid, const vec1f& chi2, const vec1f& mass, const vec1f& sfr,
        uint_t i0, uint_t i1);
    inline void fit_galaxies(const model_t& model, uint_t i0, uint_t i1);
};

// Main functions
// --------------

// fast++-read_input.cpp
bool read_input(options_t& opts, input_state_t& state, const std::string& filename);

// fast++-write_output.cpp
void write_output(const options_t& opts, const input_state_t& state, const gridder_t& gridder,
    const output_state_t& output);

// Helper functions
// ----------------

namespace phypp {
namespace file {
    template<typename S, typename T>
    bool write(S& s, const T& t) {
        s.write(reinterpret_cast<const char*>(&t), sizeof(T));
        return !s.fail();
    }

    template<typename R, typename S, typename T>
    bool write_as(S& s, const T& t) {
        R r = t;
        s.write(reinterpret_cast<const char*>(&r), sizeof(R));
        return !s.fail();
    }

    template<typename S, std::size_t D, typename T>
    bool write(S& s, const vec<D,T>& t) {
        s.write(reinterpret_cast<const char*>(t.data.data()), sizeof(T)*t.size());
        return !s.fail();
    }

    template<typename S, typename T>
    bool read(S& s, T& t) {
        s.read(reinterpret_cast<char*>(&t), sizeof(T));
        return !s.fail();
    }

    template<typename R, typename S, typename T>
    bool read_as(S& s, T& t) {
        R r;
        if (s.read(reinterpret_cast<char*>(&r), sizeof(R))) {
            t = r;
        }

        return !s.fail();
    }

    template<typename S, std::size_t D, typename T>
    bool read(S& s, vec<D,T>& t) {
        s.read(reinterpret_cast<char*>(t.data.data()), sizeof(T)*t.size());
        return !s.fail();
    }
}
}

#endif
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_pba_init.H $      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file: p9_pm_pba_init.H
/// @brief: Initialize PBA registers for modes PM_INIT, PM_RESET
///
// *HWP HWP Owner: Greg Still <stillgs@us.ibm.com>
// *HWP FW Owner: Sangeetha T S <sangeet2@in.ibm.com>
// *HWP Team: PM
// *HWP Level: 1
// *HWP Consumed by: HS
//

///
///   @verbatim
///
///       high level flow:
///           if {i_mode == PM_INIT)
///               rc =  pba_init_init(i_target);
///           else if (i_mode == PM_RESET)
///               rc =  pba_init_reset(i_target);
///   @endverbatim
///

#ifndef _P9_PBAINIT_H_
#define _P9_PBAINIT_H_

// ----------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------
#include <fapi2.H>
#include <p9_pm.H>

// ----------------------------------------------------------------------
// Constant Defintions
// ----------------------------------------------------------------------
namespace p9pba
{
// BCDE and BCUE Status registers bits
enum PBA_BC_STAT
{
    PBA_BC_STAT_RUNNING = 0
};

// Valid command scope.
enum CMD_SCOPE
{
    LOCAL_NODAL    = 0x00,
    NEAR_NODE      = 0x02,
    GROUP          = 0x03,
    REMOTE_NODE    = 0x04,
    VECTORED_GROUP = 0x5
};

// Maximum number of Polls for PBA slave reset
enum PBA_SLAVE_POLL
{
    MAX_PBA_RESET_POLLS = 16 , // in microseconds
    PBA_RESET_POLL_DELAY = 1
};

// Maximum number of Polls for PBA Block Copy Stopping - 500ms timeout
enum PBA_BLOCK_COPY_POLL
{
    MAX_PBA_BC_STOP_POLLS = 256 ,        // in microseconds
};

const uint64_t PBA_SLVRESETs[4] =
{
    0x8000000000000000ull,
    0xA000000000000000ull,
    0xC000000000000000ull,
    0xE000000000000000ull
};

// structure of values for cmd_scope, pba and pbabar initialization
struct pba_cmd_init
{
    CMD_SCOPE cmd_scope;
    uint64_t  addr;
    uint64_t  size;
};
} //namespace

// function pointer typedef definition for HWP call support
typedef fapi2::ReturnCode (*p9_pm_pba_init_FP_t)
(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>&,
 const p9pm::PM_FLOW_MODE);

extern "C" {

// ----------------------------------------------------------------------
// Function prototypes
// ----------------------------------------------------------------------

///
/// @brief Set the pba registers depending on "mode"
///
/// @param[in] i_target Chip target
/// @param[in] i_mode   Mode
///
/// @return FAPI2_RC_SUCCESS on success or error return code
///
    fapi2::ReturnCode p9_pm_pba_init
    (const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
     const p9pm::PM_FLOW_MODE i_mode);
}

#endif // _P9_PBAINIT_H_
<commit_msg>Level 3: For various PM HWP<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_pba_init.H $      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file: p9_pm_pba_init.H
/// @brief: Initialize PBA registers for modes PM_INIT, PM_RESET
///
// *HWP HWP Owner           :   Greg Still  <stillgs@us.ibm.com>
// *HWP Backup Owner        :   Prasad BG Ranganath <prasadbgr@in.ibm.com>
// *HWP FW  Owner           :   Prem S Jha <premjha2@in.ibm.com>
// *HWP Team                :   PM
// *HWP Level               :   3
// *HWP Consumed by         :   HS

#ifndef _P9_PBAINIT_H_
#define _P9_PBAINIT_H_

// ----------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------
#include <fapi2.H>
#include <p9_pm.H>

// ----------------------------------------------------------------------
// Constant Defintions
// ----------------------------------------------------------------------
namespace p9pba
{
// BCDE and BCUE Status registers bits
enum PBA_BC_STAT
{
    PBA_BC_STAT_RUNNING = 0
};

// Valid command scope.
enum CMD_SCOPE
{
    LOCAL_NODAL    = 0x00,
    NEAR_NODE      = 0x02,
    GROUP          = 0x03,
    REMOTE_NODE    = 0x04,
    VECTORED_GROUP = 0x5
};

// Maximum number of Polls for PBA slave reset
enum PBA_SLAVE_POLL
{
    MAX_PBA_RESET_POLLS = 16 , // in microseconds
    PBA_RESET_POLL_DELAY = 1
};

// Maximum number of Polls for PBA Block Copy Stopping - 500ms timeout
enum PBA_BLOCK_COPY_POLL
{
    MAX_PBA_BC_STOP_POLLS = 256 ,        // in microseconds
};

const uint64_t PBA_SLVRESETs[4] =
{
    0x8000000000000000ull,
    0xA000000000000000ull,
    0xC000000000000000ull,
    0xE000000000000000ull
};

// structure of values for cmd_scope, pba and pbabar initialization
struct pba_cmd_init
{
    CMD_SCOPE cmd_scope;
    uint64_t  addr;
    uint64_t  size;
};
} //namespace

// function pointer typedef definition for HWP call support
typedef fapi2::ReturnCode (*p9_pm_pba_init_FP_t)
(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>&,
 const p9pm::PM_FLOW_MODE);

extern "C" {

// ----------------------------------------------------------------------
// Function prototypes
// ----------------------------------------------------------------------

///
/// @brief Set the pba registers depending on "mode"
///
/// @param[in] i_target Chip target
/// @param[in] i_mode   Mode
///
/// @return FAPI2_RC_SUCCESS on success or error return code
///
    fapi2::ReturnCode p9_pm_pba_init
    (const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
     const p9pm::PM_FLOW_MODE i_mode);
}

#endif // _P9_PBAINIT_H_
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cmath>
#include <ctime>

#include "lib/font.h"
#include "lib/body.h"
#include "lib/image.h"
#include "lib/video.h"
#include "lib/output.h"
#include "lib/misc.h"
#include "lib/matrix.h"
#include "lib/units.h"

#include <pngwriter.h>

using namespace std;

int main(int argc, char * argv[]) {
	string usageStatement = "Usage: ./sombrero [-g --generate] [-r --run]";

	// Need to make these "settable" by the user
	int bodyCount = 200;
	int width = 640;
	int height = 480;

	int framerate = 45;

	Body * bodyArray [bodyCount];

	// No arguments supplied
	if (argc == 1) {
		// No arguments supplied. Exit.
		cout << "No arguments supplied. Must choose an option." << endl;
		cout << usageStatement << endl;
		return 1;
	}

	// Generate Body arrangement
	if (strcmp(argv[1], "-g") == 0 or strcmp(argv[1], "--generate") == 0) {
		if (argc >= 3) {
			// Generate random arrangement of bodies (+ generate rotation video)
			// i.e. create new bodyArray
			if (strcmp(argv[2], "random") == 0) {
				for (int i = 0; i < bodyCount - 1; i++) {
					double r = Random(1e11, 2e11);
					double theta = Random(0, 2 * PI);
					double phi = Random(0, 2 * PI);

					double x = r * cos(theta) * cos(phi);
					double y = r * sin(theta);
					double z = r * cos(theta) * sin(phi);

					double mass = Random(1e23, 1e25);

					bodyArray[i] = new Body(x, y, z, mass, Random(1e6, 9e6), Random(0, 1e4), Random(0, 1e4), Random(0, 1e4));
				}

				bodyArray[bodyCount - 1] = new Body(0.0, 0.0, 0.0, 2e31, 1e8, 0.0, 0.0, 0.0);

				// Save bodies to output.txt
				Output output("init/output.txt", bodyCount, width, height, 100);
				output.AddAllBodies(bodyArray);
				output.Save();
			}

			// Generate rotate video around bodies
			// i.e. Load bodies from file
			else if (strcmp(argv[2], "rotate") == 0) {
				string filename = "init/output.txt";

				if (argc == 4) {
					// Assume that the final argument is the filename
					filename = argv[3];
				}

				if (FileExists(filename)) {
					LoadBodiesFromFile(filename.c_str(), bodyArray);
				}
				else {
					cout << "./sombrero --generate rotate [filename]" << endl;
					cout << "When using rotate, must include valid filename: e.g. init/output.txt" << endl;
					return 1;
				}
			}

			else {
				cout << usageStatement << endl;
				cout << "Must supply generate argument: [random, rotate]" << endl;
				return 1;
			}
		}

		else {
			cout << usageStatement << endl;
			cout << "Must supply generate argument: [random, rotate]" << endl;
			return 1;
		}

		// Generate rotate video around bodies
		Video video = Video("images/", "image_", width, height, framerate);
		video.ClearImageFolder();

		// Rotate bodies about the y-axis
		for (double angle = 0.0; angle < 360.0; angle ++) {
			string imageFileName = "images/image_" + PadWithZeroes(angle, 360) + ".png";
			Image image = Image(imageFileName, width, height, 100);

			for (int i = 0; i < bodyCount; i++) {
				// Rotate body
				Vector p;
				p.Set(bodyArray[i]->GetX(), bodyArray[i]->GetY(), bodyArray[i]->GetZ());

				Vector t;
				t = p.RotateY(angle);
				t = t.RoundValues();

				image.DrawBody(t.GetX(), t.GetY(), 255, 255, 255);
			}

			image.Save();
		}

		// Build video from images
		video.Build("result.mp4", 360);

		return 0;
	}

	// Run simulation
	if (strcmp(argv[1], "-r") == 0 or strcmp(argv[1], "--run") == 0) {
		LoadBodiesFromFile("init/output.txt", bodyArray);

		Video video = Video("images/", "image_", width, height, framerate);
		video.ClearImageFolder();

		int frames = 500;
		double dt = DAY;

		for (int f = 0; f < frames; f++) {
			// Optimised algorithm
			for (int i = 0; i < bodyCount; i++) {
				if (bodyArray[i] != NULL) {
					bodyArray[i]->ResetForce();
				}
			}

			for (int a = 0; a < bodyCount; a++) {
				for (int b = a + 1; b < bodyCount; b++) {
					if (bodyArray[a] != NULL && bodyArray[b] != NULL) {
						// Calculate distance
						double xDistance = bodyArray[a]->GetX() - bodyArray[b]->GetX();
						double yDistance = bodyArray[a]->GetY() - bodyArray[b]->GetY();
						double zDistance = bodyArray[a]->GetZ() - bodyArray[b]->GetZ();
						double totalDistance = sqrt(pow(xDistance, 2) + pow(yDistance, 2) + pow(zDistance, 2));

						// Calculate angles
						double phiAngle = atan2(zDistance, sqrt(pow(xDistance, 2) + pow(yDistance, 2)));
						double thetaAngle = atan2(yDistance, xDistance);

						// Calculate force
						double force = GR * ((bodyArray[a]->GetMass() * bodyArray[b]->GetMass()) / (pow(totalDistance, 2)));

						// Add forces to totals
						bodyArray[a]->AddForce(force, phiAngle, thetaAngle);
						bodyArray[b]->AddForce(-force, phiAngle, thetaAngle);
					}
				}
			}

			string imageFileName = "images/image_" + PadWithZeroes(f, frames) + ".png";
			Image image = Image(imageFileName, width, height, 100);

			// Calculate next position for each body
			for (int i = 0; i < bodyCount; i++) {
				if (bodyArray[i] != NULL) {
					bodyArray[i]->Update(dt);
				}
			}

			// Collision Physics
			//bool firstCollision = true;
			int collisionCount = 0;

			for (int a = 0; a < bodyCount; a++) {
				for (int b = a + 1; b < bodyCount; b++) {
					if (bodyArray[a] != NULL && bodyArray[b] != NULL) {
						double collisionTime = -1;

						// Set up position vectors
						Vector initialA;
						initialA.Set(bodyArray[a]->GetX(), bodyArray[a]->GetY(), bodyArray[a]->GetZ());

						Vector finalA;
						finalA.Set(bodyArray[a]->GetNextX(), bodyArray[a]->GetNextY(), bodyArray[a]->GetNextZ());

						Vector initialB;
						initialB.Set(bodyArray[b]->GetX(), bodyArray[b]->GetY(), bodyArray[b]->GetZ());

						Vector finalB;
						finalB.Set(bodyArray[b]->GetNextX(), bodyArray[b]->GetNextY(), bodyArray[b]->GetNextZ());

						// Check the two lines are not parallel
						Vector lineA = finalA.Subtract(initialA);
						Vector lineB = finalB.Subtract(initialB);

						if (lineA.DotProduct(lineB) != 0) {
							// Calculate collision times
							Vector vectorA = initialB.Subtract(initialA);
							Vector vectorB = (finalB.Subtract(finalA)).Add(initialA.Subtract(initialB));

							double dotProduct = vectorA.DotProduct(vectorB);
							double radiiSum = bodyArray[a]->GetRadius() + bodyArray[b]->GetRadius();

							double determinant = (4 * pow(dotProduct, 2)) - (4 * pow(vectorB.Magnitude(), 2) * (pow(vectorA.Magnitude(), 2) - pow(radiiSum, 2)));
							double time1 = (-2 * dotProduct + sqrt(determinant)) / (2 * pow(vectorB.Magnitude(), 2));
							double time2 = (-2 * dotProduct - sqrt(determinant)) / (2 * pow(vectorB.Magnitude(), 2));

							bool timeValid1 = time1 >= 0 && time1 <= 1;
							bool timeValid2 = time2 >= 0 && time2 <= 1;

							// Check validity
							if (timeValid1 && timeValid2) {
								/*
								if (firstCollision == true) {
									cout << "==== FRAME " << to_string(f) << " ====" << endl;
									firstCollision = false;
								}
								*/

								collisionCount++;

								if (time1 <= time2) {
									// DEBUG
									//cout << "Collision occurs at " << to_string(time1)  << ", between [" << to_string(a) << "] and [" << to_string(b) << "]"<< endl;
									collisionTime = time1 * dt;
								}
								else {
									// DEBUG
									//cout << "Collision occurs at " << to_string(time2)  << ", between [" << to_string(a) << "] and [" << to_string(b) << "]"<< endl;
									collisionTime = time2 * dt;
								}
							}
						}

						// Collide particles if collision has occured
						if (collisionTime != -1) {
							double newMass = bodyArray[a]->GetMass() + bodyArray[b]->GetMass();

							// Conservation of linear momentum
							// X
							double aXVelocity = bodyArray[a]->GetXVelocity();
							double bXVelocity = bodyArray[b]->GetXVelocity();
							double newXVelocity = ((bodyArray[a]->GetMass() * aXVelocity) + (bodyArray[b]->GetMass() * bXVelocity)) / (newMass);

							// Y
							double aYVelocity = bodyArray[a]->GetYVelocity();
							double bYVelocity = bodyArray[b]->GetYVelocity();
							double newYVelocity = ((bodyArray[a]->GetMass() * aYVelocity) + (bodyArray[b]->GetMass() * bYVelocity)) / (newMass);

							// Z
							double aZVelocity = bodyArray[a]->GetZVelocity();
							double bZVelocity = bodyArray[b]->GetZVelocity();
							double newZVelocity = ((bodyArray[a]->GetMass() * aZVelocity) + (bodyArray[b]->GetMass() * bZVelocity)) / (newMass);

							// Calculate new position
							// Use midpoint of the two "new positions"
							bodyArray[a]->Update(collisionTime);
							bodyArray[b]->Update(collisionTime);

							double newX = (bodyArray[a]->GetNextX() + bodyArray[b]->GetNextX()) / 2;
							double newY = (bodyArray[a]->GetNextY() + bodyArray[b]->GetNextY()) / 2;
							double newZ = (bodyArray[a]->GetNextZ() + bodyArray[b]->GetNextZ()) / 2;

							// Calculate new radius
							// TODO: Figure out way of calculating a new radius given constant density?
							// At the moment, use larger radius of the two bodies
							double newRadius;
							if (bodyArray[a]->GetRadius() >= bodyArray[b]->GetRadius()) {
								newRadius = bodyArray[a]->GetRadius();
							}
							else {
								newRadius = bodyArray[b]->GetRadius();
							}

							// Remove a and b and create new body;
							int newIndex;
							int otherIndex;

							if (a < b) {
								newIndex = a;
								otherIndex = b;
							}
							else {
								newIndex = b;
								otherIndex = a;
							}

							bodyArray[newIndex] = new Body(newX, newY, newZ, newMass, newRadius, newXVelocity, newYVelocity, newZVelocity);
							bodyArray[newIndex]->Update(dt - collisionTime);

							bodyArray[otherIndex] = NULL;
						}
					}
				}
			}

			// DEBUG
			/*
			if (firstCollision == false) {
				cout << endl;
			}
			*/

			cout << "Frame " << f << ": " << collisionCount << endl;

			// Move each body to their new positions
			for (int i = 0; i < bodyCount; i++) {
				if (bodyArray[i] != NULL) {
					bodyArray[i]->Step();

					image.DrawBody(bodyArray[i]->GetX(), bodyArray[i]->GetY(), 255, 255, 255);
				}
			}

			// Draw information on frame
			image.DrawText("F: " + to_string(f), 10, 10, 255, 255, 255);

			image.Save();
		}

		video.Build("result_run.mp4", frames);

		// Create output.txt
		Output output("init/output.txt", bodyCount, width, height, 100);
		output.AddAllBodies(bodyArray);
		output.Save();

		return 0;
	}

	// No *valid* arguments supplied
	else {
		cout << "No valid arguments provided." << endl;
		cout << usageStatement << endl;
		return 1;
	}

	return 0;
}
<commit_msg>Removed debug statements and added body counter to output video<commit_after>#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cmath>
#include <ctime>

#include "lib/font.h"
#include "lib/body.h"
#include "lib/image.h"
#include "lib/video.h"
#include "lib/output.h"
#include "lib/misc.h"
#include "lib/matrix.h"
#include "lib/units.h"

#include <pngwriter.h>

using namespace std;

int main(int argc, char * argv[]) {
	string usageStatement = "Usage: ./sombrero [-g --generate] [-r --run]";

	// Need to make these "settable" by the user
	int bodyCount = 200;
	int width = 640;
	int height = 480;

	int framerate = 45;

	Body * bodyArray [bodyCount];

	// No arguments supplied
	if (argc == 1) {
		// No arguments supplied. Exit.
		cout << "No arguments supplied. Must choose an option." << endl;
		cout << usageStatement << endl;
		return 1;
	}

	// Generate Body arrangement
	if (strcmp(argv[1], "-g") == 0 or strcmp(argv[1], "--generate") == 0) {
		if (argc >= 3) {
			// Generate random arrangement of bodies (+ generate rotation video)
			// i.e. create new bodyArray
			if (strcmp(argv[2], "random") == 0) {
				for (int i = 0; i < bodyCount - 1; i++) {
					double r = Random(1e11, 2e11);
					double theta = Random(0, 2 * PI);
					double phi = Random(0, 2 * PI);

					double x = r * cos(theta) * cos(phi);
					double y = r * sin(theta);
					double z = r * cos(theta) * sin(phi);

					double mass = Random(1e23, 1e25);

					bodyArray[i] = new Body(x, y, z, mass, Random(1e6, 9e6), Random(0, 1e4), Random(0, 1e4), Random(0, 1e4));
				}

				bodyArray[bodyCount - 1] = new Body(0.0, 0.0, 0.0, 2e31, 1e8, 0.0, 0.0, 0.0);

				// Save bodies to output.txt
				Output output("init/output.txt", bodyCount, width, height, 100);
				output.AddAllBodies(bodyArray);
				output.Save();
			}

			// Generate rotate video around bodies
			// i.e. Load bodies from file
			else if (strcmp(argv[2], "rotate") == 0) {
				string filename = "init/output.txt";

				if (argc == 4) {
					// Assume that the final argument is the filename
					filename = argv[3];
				}

				if (FileExists(filename)) {
					LoadBodiesFromFile(filename.c_str(), bodyArray);
				}
				else {
					cout << "./sombrero --generate rotate [filename]" << endl;
					cout << "When using rotate, must include valid filename: e.g. init/output.txt" << endl;
					return 1;
				}
			}

			else {
				cout << usageStatement << endl;
				cout << "Must supply generate argument: [random, rotate]" << endl;
				return 1;
			}
		}

		else {
			cout << usageStatement << endl;
			cout << "Must supply generate argument: [random, rotate]" << endl;
			return 1;
		}

		// Generate rotate video around bodies
		Video video = Video("images/", "image_", width, height, framerate);
		video.ClearImageFolder();

		// Rotate bodies about the y-axis
		for (double angle = 0.0; angle < 360.0; angle ++) {
			string imageFileName = "images/image_" + PadWithZeroes(angle, 360) + ".png";
			Image image = Image(imageFileName, width, height, 100);

			for (int i = 0; i < bodyCount; i++) {
				// Rotate body
				Vector p;
				p.Set(bodyArray[i]->GetX(), bodyArray[i]->GetY(), bodyArray[i]->GetZ());

				Vector t;
				t = p.RotateY(angle);
				t = t.RoundValues();

				image.DrawBody(t.GetX(), t.GetY(), 255, 255, 255);
			}

			image.Save();
		}

		// Build video from images
		video.Build("result.mp4", 360);

		return 0;
	}

	// Run simulation
	if (strcmp(argv[1], "-r") == 0 or strcmp(argv[1], "--run") == 0) {
		LoadBodiesFromFile("init/output.txt", bodyArray);

		Video video = Video("images/", "image_", width, height, framerate);
		video.ClearImageFolder();

		int frames = 500;
		double dt = DAY / 2;
		double numberOfBodies = bodyCount;

		for (int f = 0; f < frames; f++) {
			// Optimised algorithm
			for (int i = 0; i < bodyCount; i++) {
				if (bodyArray[i] != NULL) {
					bodyArray[i]->ResetForce();
				}
			}

			for (int a = 0; a < bodyCount; a++) {
				for (int b = a + 1; b < bodyCount; b++) {
					if (bodyArray[a] != NULL && bodyArray[b] != NULL) {
						// Calculate distance
						double xDistance = bodyArray[a]->GetX() - bodyArray[b]->GetX();
						double yDistance = bodyArray[a]->GetY() - bodyArray[b]->GetY();
						double zDistance = bodyArray[a]->GetZ() - bodyArray[b]->GetZ();
						double totalDistance = sqrt(pow(xDistance, 2) + pow(yDistance, 2) + pow(zDistance, 2));

						// Calculate angles
						double phiAngle = atan2(zDistance, sqrt(pow(xDistance, 2) + pow(yDistance, 2)));
						double thetaAngle = atan2(yDistance, xDistance);

						// Calculate force
						double force = GR * ((bodyArray[a]->GetMass() * bodyArray[b]->GetMass()) / (pow(totalDistance, 2)));

						// Add forces to totals
						bodyArray[a]->AddForce(force, phiAngle, thetaAngle);
						bodyArray[b]->AddForce(-force, phiAngle, thetaAngle);
					}
				}
			}

			string imageFileName = "images/image_" + PadWithZeroes(f, frames) + ".png";
			Image image = Image(imageFileName, width, height, 100);

			// Calculate next position for each body
			for (int i = 0; i < bodyCount; i++) {
				if (bodyArray[i] != NULL) {
					bodyArray[i]->Update(dt);
				}
			}

			// Collision Physics
			for (int a = 0; a < bodyCount; a++) {
				for (int b = a + 1; b < bodyCount; b++) {
					if (bodyArray[a] != NULL && bodyArray[b] != NULL) {
						double collisionTime = -1;

						// Set up position vectors
						Vector initialA;
						initialA.Set(bodyArray[a]->GetX(), bodyArray[a]->GetY(), bodyArray[a]->GetZ());

						Vector finalA;
						finalA.Set(bodyArray[a]->GetNextX(), bodyArray[a]->GetNextY(), bodyArray[a]->GetNextZ());

						Vector initialB;
						initialB.Set(bodyArray[b]->GetX(), bodyArray[b]->GetY(), bodyArray[b]->GetZ());

						Vector finalB;
						finalB.Set(bodyArray[b]->GetNextX(), bodyArray[b]->GetNextY(), bodyArray[b]->GetNextZ());

						// Check the two lines are not parallel
						Vector lineA = finalA.Subtract(initialA);
						Vector lineB = finalB.Subtract(initialB);

						if (lineA.DotProduct(lineB) != 0) {
							// Calculate collision times
							Vector vectorA = initialB.Subtract(initialA);
							Vector vectorB = (finalB.Subtract(finalA)).Add(initialA.Subtract(initialB));

							double dotProduct = vectorA.DotProduct(vectorB);
							double radiiSum = bodyArray[a]->GetRadius() + bodyArray[b]->GetRadius();

							double determinant = (4 * pow(dotProduct, 2)) - (4 * pow(vectorB.Magnitude(), 2) * (pow(vectorA.Magnitude(), 2) - pow(radiiSum, 2)));
							double time1 = (-2 * dotProduct + sqrt(determinant)) / (2 * pow(vectorB.Magnitude(), 2));
							double time2 = (-2 * dotProduct - sqrt(determinant)) / (2 * pow(vectorB.Magnitude(), 2));

							bool timeValid1 = time1 >= 0 && time1 <= 1;
							bool timeValid2 = time2 >= 0 && time2 <= 1;

							// Check validity
							if (timeValid1 && timeValid2) {
								if (time1 <= time2) {
									collisionTime = time1 * dt;
								}
								else {
									collisionTime = time2 * dt;
								}
							}
						}

						// Collide particles if collision has occured
						if (collisionTime != -1) {
							double newMass = bodyArray[a]->GetMass() + bodyArray[b]->GetMass();

							// Conservation of linear momentum
							// X
							double aXVelocity = bodyArray[a]->GetXVelocity();
							double bXVelocity = bodyArray[b]->GetXVelocity();
							double newXVelocity = ((bodyArray[a]->GetMass() * aXVelocity) + (bodyArray[b]->GetMass() * bXVelocity)) / (newMass);

							// Y
							double aYVelocity = bodyArray[a]->GetYVelocity();
							double bYVelocity = bodyArray[b]->GetYVelocity();
							double newYVelocity = ((bodyArray[a]->GetMass() * aYVelocity) + (bodyArray[b]->GetMass() * bYVelocity)) / (newMass);

							// Z
							double aZVelocity = bodyArray[a]->GetZVelocity();
							double bZVelocity = bodyArray[b]->GetZVelocity();
							double newZVelocity = ((bodyArray[a]->GetMass() * aZVelocity) + (bodyArray[b]->GetMass() * bZVelocity)) / (newMass);

							// Calculate new position
							// Use midpoint of the two "new positions"
							bodyArray[a]->Update(collisionTime);
							bodyArray[b]->Update(collisionTime);

							double newX = (bodyArray[a]->GetNextX() + bodyArray[b]->GetNextX()) / 2;
							double newY = (bodyArray[a]->GetNextY() + bodyArray[b]->GetNextY()) / 2;
							double newZ = (bodyArray[a]->GetNextZ() + bodyArray[b]->GetNextZ()) / 2;

							// Calculate new radius
							// TODO: Figure out way of calculating a new radius given constant density?
							// At the moment, use larger radius of the two bodies
							double newRadius;
							if (bodyArray[a]->GetRadius() >= bodyArray[b]->GetRadius()) {
								newRadius = bodyArray[a]->GetRadius();
							}
							else {
								newRadius = bodyArray[b]->GetRadius();
							}

							// Remove a and b and create new body;
							int newIndex;
							int otherIndex;

							if (a < b) {
								newIndex = a;
								otherIndex = b;
							}
							else {
								newIndex = b;
								otherIndex = a;
							}

							bodyArray[newIndex] = new Body(newX, newY, newZ, newMass, newRadius, newXVelocity, newYVelocity, newZVelocity);
							bodyArray[newIndex]->Update(dt - collisionTime);

							bodyArray[otherIndex] = NULL;

							numberOfBodies--;
						}
					}
				}
			}

			// Move each body to their new positions
			for (int i = 0; i < bodyCount; i++) {
				if (bodyArray[i] != NULL) {
					bodyArray[i]->Step();

					image.DrawBody(bodyArray[i]->GetX(), bodyArray[i]->GetY(), 255, 255, 255);
				}
			}

			// Draw information on frame
			image.DrawText("F: " + to_string(f), 10, 10, 255, 255, 255);
			image.DrawText("N: " + to_string(numberOfBodies), 10, 20, 255, 255, 255);

			image.Save();
		}

		video.Build("result_run.mp4", frames);

		// Create output.txt
		Output output("init/output.txt", bodyCount, width, height, 100);
		output.AddAllBodies(bodyArray);
		output.Save();

		return 0;
	}

	// No *valid* arguments supplied
	else {
		cout << "No valid arguments provided." << endl;
		cout << usageStatement << endl;
		return 1;
	}

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2004-2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Kevin Lim
 */

#include "base/intmath.hh"
#include "cpu/pred/tournament.hh"

TournamentBP::TournamentBP(unsigned _localPredictorSize,
                           unsigned _localCtrBits,
                           unsigned _localHistoryTableSize,
                           unsigned _localHistoryBits,
                           unsigned _globalPredictorSize,
                           unsigned _globalCtrBits,
                           unsigned _globalHistoryBits,
                           unsigned _choicePredictorSize,
                           unsigned _choiceCtrBits,
                           unsigned _instShiftAmt)
    : localPredictorSize(_localPredictorSize),
      localCtrBits(_localCtrBits),
      localHistoryTableSize(_localHistoryTableSize),
      localHistoryBits(_localHistoryBits),
      globalPredictorSize(_globalPredictorSize),
      globalCtrBits(_globalCtrBits),
      globalHistoryBits(_globalHistoryBits),
      choicePredictorSize(_globalPredictorSize),
      choiceCtrBits(_choiceCtrBits),
      instShiftAmt(_instShiftAmt)
{
    if (!isPowerOf2(localPredictorSize)) {
        fatal("Invalid local predictor size!\n");
    }

    //Setup the array of counters for the local predictor
    localCtrs.resize(localPredictorSize);

    for (int i = 0; i < localPredictorSize; ++i)
        localCtrs[i].setBits(localCtrBits);

    localPredictorMask = floorPow2(localPredictorSize) - 1;

    if (!isPowerOf2(localHistoryTableSize)) {
        fatal("Invalid local history table size!\n");
    }

    //Setup the history table for the local table
    localHistoryTable.resize(localHistoryTableSize);

    for (int i = 0; i < localHistoryTableSize; ++i)
        localHistoryTable[i] = 0;

    // Setup the local history mask
    localHistoryMask = (1 << localHistoryBits) - 1;

    if (!isPowerOf2(globalPredictorSize)) {
        fatal("Invalid global predictor size!\n");
    }

    //Setup the array of counters for the global predictor
    globalCtrs.resize(globalPredictorSize);

    for (int i = 0; i < globalPredictorSize; ++i)
        globalCtrs[i].setBits(globalCtrBits);

    //Clear the global history
    globalHistory = 0;
    // Setup the global history mask
    globalHistoryMask = (1 << globalHistoryBits) - 1;

    if (!isPowerOf2(choicePredictorSize)) {
        fatal("Invalid choice predictor size!\n");
    }

    //Setup the array of counters for the choice predictor
    choiceCtrs.resize(choicePredictorSize);

    for (int i = 0; i < choicePredictorSize; ++i)
        choiceCtrs[i].setBits(choiceCtrBits);

    // @todo: Allow for different thresholds between the predictors.
    threshold = (1 << (localCtrBits - 1)) - 1;
    threshold = threshold / 2;
}

inline
unsigned
TournamentBP::calcLocHistIdx(Addr &branch_addr)
{
    // Get low order bits after removing instruction offset.
    return (branch_addr >> instShiftAmt) & (localHistoryTableSize - 1);
}

inline
void
TournamentBP::updateGlobalHistTaken()
{
    globalHistory = (globalHistory << 1) | 1;
    globalHistory = globalHistory & globalHistoryMask;
}

inline
void
TournamentBP::updateGlobalHistNotTaken()
{
    globalHistory = (globalHistory << 1);
    globalHistory = globalHistory & globalHistoryMask;
}

inline
void
TournamentBP::updateLocalHistTaken(unsigned local_history_idx)
{
    localHistoryTable[local_history_idx] =
        (localHistoryTable[local_history_idx] << 1) | 1;
}

inline
void
TournamentBP::updateLocalHistNotTaken(unsigned local_history_idx)
{
    localHistoryTable[local_history_idx] =
        (localHistoryTable[local_history_idx] << 1);
}

bool
TournamentBP::lookup(Addr &branch_addr, void * &bp_history)
{
    bool local_prediction;
    unsigned local_history_idx;
    unsigned local_predictor_idx;

    bool global_prediction;
    bool choice_prediction;

    //Lookup in the local predictor to get its branch prediction
    local_history_idx = calcLocHistIdx(branch_addr);
    local_predictor_idx = localHistoryTable[local_history_idx]
        & localPredictorMask;
    local_prediction = localCtrs[local_predictor_idx].read() > threshold;

    //Lookup in the global predictor to get its branch prediction
    global_prediction = globalCtrs[globalHistory].read() > threshold;

    //Lookup in the choice predictor to see which one to use
    choice_prediction = choiceCtrs[globalHistory].read() > threshold;

    // Create BPHistory and pass it back to be recorded.
    BPHistory *history = new BPHistory;
    history->globalHistory = globalHistory;
    history->localPredTaken = local_prediction;
    history->globalPredTaken = global_prediction;
    history->globalUsed = choice_prediction;
    bp_history = (void *)history;

    assert(globalHistory < globalPredictorSize &&
           local_history_idx < localHistoryTableSize &&
           local_predictor_idx < localPredictorSize);

    // Commented code is for doing speculative update of counters and
    // all histories.
    if (choice_prediction) {
        if (global_prediction) {
//            updateHistoriesTaken(local_history_idx);
//            globalCtrs[globalHistory].increment();
//            localCtrs[local_history_idx].increment();
            updateGlobalHistTaken();
            return true;
        } else {
//            updateHistoriesNotTaken(local_history_idx);
//            globalCtrs[globalHistory].decrement();
//            localCtrs[local_history_idx].decrement();
            updateGlobalHistNotTaken();
            return false;
        }
    } else {
        if (local_prediction) {
//            updateHistoriesTaken(local_history_idx);
//            globalCtrs[globalHistory].increment();
//            localCtrs[local_history_idx].increment();
            updateGlobalHistTaken();
            return true;
        } else {
//            updateHistoriesNotTaken(local_history_idx);
//            globalCtrs[globalHistory].decrement();
//            localCtrs[local_history_idx].decrement();
            updateGlobalHistNotTaken();
            return false;
        }
    }
}

void
TournamentBP::uncondBr(void * &bp_history)
{
    // Create BPHistory and pass it back to be recorded.
    BPHistory *history = new BPHistory;
    history->globalHistory = globalHistory;
    history->localPredTaken = true;
    history->globalPredTaken = true;
    bp_history = static_cast<void *>(history);

    updateGlobalHistTaken();
}

void
TournamentBP::update(Addr &branch_addr, bool taken, void *bp_history)
{
    unsigned local_history_idx;
    unsigned local_predictor_idx;
    unsigned local_predictor_hist;

    // Get the local predictor's current prediction
    local_history_idx = calcLocHistIdx(branch_addr);
    local_predictor_hist = localHistoryTable[local_history_idx];
    local_predictor_idx = local_predictor_hist & localPredictorMask;

    // Update the choice predictor to tell it which one was correct if
    // there was a prediction.
    if (bp_history) {
        BPHistory *history = static_cast<BPHistory *>(bp_history);
        if (history->localPredTaken != history->globalPredTaken) {
            // If the local prediction matches the actual outcome,
            // decerement the counter.  Otherwise increment the
            // counter.
            if (history->localPredTaken == taken) {
                choiceCtrs[globalHistory].decrement();
            } else if (history->globalPredTaken == taken){
                choiceCtrs[globalHistory].increment();
            }
        }

        // We're done with this history, now delete it.
        delete history;
    }

    assert(globalHistory < globalPredictorSize &&
           local_history_idx < localHistoryTableSize &&
           local_predictor_idx < localPredictorSize);

    // Update the counters and local history with the proper
    // resolution of the branch.  Global history is updated
    // speculatively and restored upon squash() calls, so it does not
    // need to be updated.
    if (taken) {
        localCtrs[local_predictor_idx].increment();
        globalCtrs[globalHistory].increment();

        updateLocalHistTaken(local_history_idx);
    } else {
        localCtrs[local_predictor_idx].decrement();
        globalCtrs[globalHistory].decrement();

        updateLocalHistNotTaken(local_history_idx);
    }
}

void
TournamentBP::squash(void *bp_history)
{
    BPHistory *history = static_cast<BPHistory *>(bp_history);

    // Restore global history to state prior to this branch.
    globalHistory = history->globalHistory;

    // Delete this BPHistory now that we're done with it.
    delete history;
}

#ifdef DEBUG
int
TournamentBP::BPHistory::newCount = 0;
#endif
<commit_msg>BPRED: Fixed the treshold-bug in the tournament predictor.<commit_after>/*
 * Copyright (c) 2004-2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Kevin Lim
 */

#include "base/intmath.hh"
#include "cpu/pred/tournament.hh"

TournamentBP::TournamentBP(unsigned _localPredictorSize,
                           unsigned _localCtrBits,
                           unsigned _localHistoryTableSize,
                           unsigned _localHistoryBits,
                           unsigned _globalPredictorSize,
                           unsigned _globalCtrBits,
                           unsigned _globalHistoryBits,
                           unsigned _choicePredictorSize,
                           unsigned _choiceCtrBits,
                           unsigned _instShiftAmt)
    : localPredictorSize(_localPredictorSize),
      localCtrBits(_localCtrBits),
      localHistoryTableSize(_localHistoryTableSize),
      localHistoryBits(_localHistoryBits),
      globalPredictorSize(_globalPredictorSize),
      globalCtrBits(_globalCtrBits),
      globalHistoryBits(_globalHistoryBits),
      choicePredictorSize(_globalPredictorSize),
      choiceCtrBits(_choiceCtrBits),
      instShiftAmt(_instShiftAmt)
{
    if (!isPowerOf2(localPredictorSize)) {
        fatal("Invalid local predictor size!\n");
    }

    //Setup the array of counters for the local predictor
    localCtrs.resize(localPredictorSize);

    for (int i = 0; i < localPredictorSize; ++i)
        localCtrs[i].setBits(localCtrBits);

    localPredictorMask = floorPow2(localPredictorSize) - 1;

    if (!isPowerOf2(localHistoryTableSize)) {
        fatal("Invalid local history table size!\n");
    }

    //Setup the history table for the local table
    localHistoryTable.resize(localHistoryTableSize);

    for (int i = 0; i < localHistoryTableSize; ++i)
        localHistoryTable[i] = 0;

    // Setup the local history mask
    localHistoryMask = (1 << localHistoryBits) - 1;

    if (!isPowerOf2(globalPredictorSize)) {
        fatal("Invalid global predictor size!\n");
    }

    //Setup the array of counters for the global predictor
    globalCtrs.resize(globalPredictorSize);

    for (int i = 0; i < globalPredictorSize; ++i)
        globalCtrs[i].setBits(globalCtrBits);

    //Clear the global history
    globalHistory = 0;
    // Setup the global history mask
    globalHistoryMask = (1 << globalHistoryBits) - 1;

    if (!isPowerOf2(choicePredictorSize)) {
        fatal("Invalid choice predictor size!\n");
    }

    //Setup the array of counters for the choice predictor
    choiceCtrs.resize(choicePredictorSize);

    for (int i = 0; i < choicePredictorSize; ++i)
        choiceCtrs[i].setBits(choiceCtrBits);

    // @todo: Allow for different thresholds between the predictors.
    threshold = (1 << (localCtrBits - 1)) - 1;
}

inline
unsigned
TournamentBP::calcLocHistIdx(Addr &branch_addr)
{
    // Get low order bits after removing instruction offset.
    return (branch_addr >> instShiftAmt) & (localHistoryTableSize - 1);
}

inline
void
TournamentBP::updateGlobalHistTaken()
{
    globalHistory = (globalHistory << 1) | 1;
    globalHistory = globalHistory & globalHistoryMask;
}

inline
void
TournamentBP::updateGlobalHistNotTaken()
{
    globalHistory = (globalHistory << 1);
    globalHistory = globalHistory & globalHistoryMask;
}

inline
void
TournamentBP::updateLocalHistTaken(unsigned local_history_idx)
{
    localHistoryTable[local_history_idx] =
        (localHistoryTable[local_history_idx] << 1) | 1;
}

inline
void
TournamentBP::updateLocalHistNotTaken(unsigned local_history_idx)
{
    localHistoryTable[local_history_idx] =
        (localHistoryTable[local_history_idx] << 1);
}

bool
TournamentBP::lookup(Addr &branch_addr, void * &bp_history)
{
    bool local_prediction;
    unsigned local_history_idx;
    unsigned local_predictor_idx;

    bool global_prediction;
    bool choice_prediction;

    //Lookup in the local predictor to get its branch prediction
    local_history_idx = calcLocHistIdx(branch_addr);
    local_predictor_idx = localHistoryTable[local_history_idx]
        & localPredictorMask;
    local_prediction = localCtrs[local_predictor_idx].read() > threshold;

    //Lookup in the global predictor to get its branch prediction
    global_prediction = globalCtrs[globalHistory].read() > threshold;

    //Lookup in the choice predictor to see which one to use
    choice_prediction = choiceCtrs[globalHistory].read() > threshold;

    // Create BPHistory and pass it back to be recorded.
    BPHistory *history = new BPHistory;
    history->globalHistory = globalHistory;
    history->localPredTaken = local_prediction;
    history->globalPredTaken = global_prediction;
    history->globalUsed = choice_prediction;
    bp_history = (void *)history;

    assert(globalHistory < globalPredictorSize &&
           local_history_idx < localHistoryTableSize &&
           local_predictor_idx < localPredictorSize);

    // Commented code is for doing speculative update of counters and
    // all histories.
    if (choice_prediction) {
        if (global_prediction) {
//            updateHistoriesTaken(local_history_idx);
//            globalCtrs[globalHistory].increment();
//            localCtrs[local_history_idx].increment();
            updateGlobalHistTaken();
            return true;
        } else {
//            updateHistoriesNotTaken(local_history_idx);
//            globalCtrs[globalHistory].decrement();
//            localCtrs[local_history_idx].decrement();
            updateGlobalHistNotTaken();
            return false;
        }
    } else {
        if (local_prediction) {
//            updateHistoriesTaken(local_history_idx);
//            globalCtrs[globalHistory].increment();
//            localCtrs[local_history_idx].increment();
            updateGlobalHistTaken();
            return true;
        } else {
//            updateHistoriesNotTaken(local_history_idx);
//            globalCtrs[globalHistory].decrement();
//            localCtrs[local_history_idx].decrement();
            updateGlobalHistNotTaken();
            return false;
        }
    }
}

void
TournamentBP::uncondBr(void * &bp_history)
{
    // Create BPHistory and pass it back to be recorded.
    BPHistory *history = new BPHistory;
    history->globalHistory = globalHistory;
    history->localPredTaken = true;
    history->globalPredTaken = true;
    bp_history = static_cast<void *>(history);

    updateGlobalHistTaken();
}

void
TournamentBP::update(Addr &branch_addr, bool taken, void *bp_history)
{
    unsigned local_history_idx;
    unsigned local_predictor_idx;
    unsigned local_predictor_hist;

    // Get the local predictor's current prediction
    local_history_idx = calcLocHistIdx(branch_addr);
    local_predictor_hist = localHistoryTable[local_history_idx];
    local_predictor_idx = local_predictor_hist & localPredictorMask;

    // Update the choice predictor to tell it which one was correct if
    // there was a prediction.
    if (bp_history) {
        BPHistory *history = static_cast<BPHistory *>(bp_history);
        if (history->localPredTaken != history->globalPredTaken) {
            // If the local prediction matches the actual outcome,
            // decerement the counter.  Otherwise increment the
            // counter.
            if (history->localPredTaken == taken) {
                choiceCtrs[globalHistory].decrement();
            } else if (history->globalPredTaken == taken){
                choiceCtrs[globalHistory].increment();
            }
        }

        // We're done with this history, now delete it.
        delete history;
    }

    assert(globalHistory < globalPredictorSize &&
           local_history_idx < localHistoryTableSize &&
           local_predictor_idx < localPredictorSize);

    // Update the counters and local history with the proper
    // resolution of the branch.  Global history is updated
    // speculatively and restored upon squash() calls, so it does not
    // need to be updated.
    if (taken) {
        localCtrs[local_predictor_idx].increment();
        globalCtrs[globalHistory].increment();

        updateLocalHistTaken(local_history_idx);
    } else {
        localCtrs[local_predictor_idx].decrement();
        globalCtrs[globalHistory].decrement();

        updateLocalHistNotTaken(local_history_idx);
    }
}

void
TournamentBP::squash(void *bp_history)
{
    BPHistory *history = static_cast<BPHistory *>(bp_history);

    // Restore global history to state prior to this branch.
    globalHistory = history->globalHistory;

    // Delete this BPHistory now that we're done with it.
    delete history;
}

#ifdef DEBUG
int
TournamentBP::BPHistory::newCount = 0;
#endif
<|endoftext|>


<commit_before>#pragma once

#include <loom/protobuf.hpp>
#include <loom/protobuf_stream.hpp>
#include <loom/product_value.hpp>

namespace loom
{

class Sparsifier
{
public:

    Sparsifier (
            const protobuf::Config::Sparsify & config,
            const ValueSchema & schema) :
        config_(config),
        schema_(schema),
        unobserved_(get_unobserved(schema)),
        row_count_(0),
        booleans_(schema.booleans_size),
        counts_(schema.counts_size),
        tare_()
    {
        LOOM_ASSERT(config.run(), "sparsify is not configured to run");
    }

    void add_rows (const char * rows_in)
    {
        protobuf::InFile rows(rows_in);
        protobuf::Row row;
        while (rows.try_read_stream(row)) {
            LOOM_ASSERT(not row.has_diff(), "row is already sparsified");
            const auto & value = row.data();
            LOOM_ASSERT_EQ(
                value.observed().sparsity(),
                ProductValue::Observed::DENSE);

            auto observed = value.observed().dense().begin();
            for (size_t i = 0; i < schema_.booleans_size; ++i) {
                if (*observed++) {
                    booleans_[i].add(value.booleans(i));
                }
            }
            for (size_t i = 0; i < schema_.counts_size; ++i) {
                if (*observed++) {
                    counts_[i].add(value.counts(i));
                }
            }
            ++row_count_;
        }
    }

    const ProductValue & tare ()
    {
        tare_.Clear();
        tare_.mutable_observed()->set_sparsity(ProductValue::Observed::DENSE);

        tare_type(booleans_, * tare_.mutable_booleans());
        tare_type(counts_, * tare_.mutable_counts());

        return tare_;
    }

    void sparsify_rows (
        const char * rows_in,
        const char * diffs_out) const
    {
        LOOM_ASSERT(
            std::string(rows_in) != std::string(diffs_out),
            "in-place sparsify is not supported");
        protobuf::InFile rows(rows_in);
        protobuf::OutFile diffs(diffs_out);
        protobuf::Row row;
        protobuf::Row diff;
        const float sparse_threshold = config_.sparse_threshold();
        while (rows.try_read_stream(row)) {
            diff.Clear();
            diff.set_id(row.id());
            * diff.mutable_data()->mutable_observed() = unobserved_;
            * diff.mutable_diff()->mutable_observed() = unobserved_;

            TODO("compute diff");

            schema_.normalize_small(* diff.mutable_data(), sparse_threshold);
            schema_.normalize_small(* diff.mutable_diff(), sparse_threshold);
            diffs.write_stream(diff);
        }
    }

private:

    struct BooleanSummary
    {
        typedef uint32_t Value;
        size_t counts[2];

        BooleanSummary () : counts({0, 0}) {}
        void add (Value value) { ++counts[value]; }
        Value get_mode () const { return counts[1] > counts[0]; }
        size_t get_count (Value value) const { return counts[value]; }
    };

    struct CountSummary
    {
        enum { max_count = 16 };  // assume mode lies in [0, max_count)

        typedef uint32_t Value;
        size_t counts[max_count];

        CountSummary () { std::fill(counts, counts + max_count, 0); }

        void add (uint32_t value)
        {
            if (value < max_count) {
                ++counts[value];
            }
        }

        uint32_t get_mode () const
        {
            uint32_t value = 0;
            for (size_t i = 0; i < max_count; ++i) {
                if (counts[i] > counts[value]) {
                    value = i;
                }
            }
            return value;
        }

        uint32_t get_count (Value value) const
        {
            LOOM_ASSERT_LT(value, max_count);
            return counts[value];
        }
    };

    static protobuf::ProductValue::Observed get_unobserved (
            const ValueSchema & schema)
    {
        protobuf::ProductValue::Observed unobserved;
        unobserved.set_sparsity(ProductValue::Observed::DENSE);
        for (size_t i = 0; i < schema.total_size(); ++i) {
            unobserved.add_dense(false);
        }
        return unobserved;
    }

    template<class Summaries, class Values>
    void tare_type (const Summaries & summaries, Values & values)
    {
        const float count_threshold = config_.tare_threshold() * row_count_;
        for (const auto & summary : summaries) {
            const auto mode = summary.get_mode();
            bool is_dense = (summary.get_count(mode) > count_threshold);
            tare_.mutable_observed()->add_dense(is_dense);
            if (is_dense) {
                values.Add(mode);
            }
        }
    }

    const protobuf::Config::Sparsify & config_;
    const ValueSchema & schema_;
    const protobuf::ProductValue::Observed unobserved_;
    size_t row_count_;
    std::vector<BooleanSummary> booleans_;
    std::vector<CountSummary> counts_;
    protobuf::ProductValue tare_;
};

} // namespace loom
<commit_msg>Implement sparsify_rows (still broken)<commit_after>#pragma once

#include <loom/protobuf.hpp>
#include <loom/protobuf_stream.hpp>
#include <loom/product_value.hpp>

namespace loom
{

class Sparsifier
{
public:

    Sparsifier (
            const protobuf::Config::Sparsify & config,
            const ValueSchema & schema) :
        config_(config),
        schema_(schema),
        unobserved_(get_unobserved(schema)),
        row_count_(0),
        booleans_(schema.booleans_size),
        counts_(schema.counts_size),
        tare_()
    {
        LOOM_ASSERT(config.run(), "sparsify is not configured to run");
    }

    void add_rows (const char * rows_in)
    {
        protobuf::InFile rows(rows_in);
        protobuf::Row row;
        while (rows.try_read_stream(row)) {
            LOOM_ASSERT(not row.has_diff(), "row is already sparsified");
            const auto & value = row.data();
            LOOM_ASSERT_EQ(
                value.observed().sparsity(),
                ProductValue::Observed::DENSE);

            auto observed = value.observed().dense().begin();
            for (size_t i = 0; i < schema_.booleans_size; ++i) {
                if (*observed++) {
                    booleans_[i].add(value.booleans(i));
                }
            }
            for (size_t i = 0; i < schema_.counts_size; ++i) {
                if (*observed++) {
                    counts_[i].add(value.counts(i));
                }
            }
            ++row_count_;
        }
    }

    const ProductValue & tare ()
    {
        tare_.Clear();
        tare_.mutable_observed()->set_sparsity(ProductValue::Observed::DENSE);

        tare_type(booleans_, * tare_.mutable_booleans());
        tare_type(counts_, * tare_.mutable_counts());

        return tare_;
    }

    void sparsify_rows (
        const char * rows_in,
        const char * diffs_out) const
    {
        LOOM_ASSERT(
            std::string(rows_in) != std::string(diffs_out),
            "in-place sparsify is not supported");
        protobuf::InFile rows(rows_in);
        protobuf::OutFile diffs(diffs_out);
        protobuf::Row row;
        protobuf::Row diff;
        const float sparse_threshold = config_.sparse_threshold();
        while (rows.try_read_stream(row)) {
            diff.Clear();
            diff.set_id(row.id());
            auto & pos = * diff.mutable_data();
            auto & neg = * diff.mutable_diff();
            * pos.mutable_observed() = unobserved_;
            * neg.mutable_observed() = unobserved_;

            size_t begin = 0;
            size_t end = schema_.booleans_size;
            sparsify_type<bool>(begin, end, row.data(), tare_, pos, neg);

            begin = end;
            end += schema_.counts_size;
            sparsify_type<uint32_t>(begin, end, row.data(), tare_, pos, neg);

            schema_.normalize_small(* diff.mutable_data(), sparse_threshold);
            schema_.normalize_small(* diff.mutable_diff(), sparse_threshold);
            diffs.write_stream(diff);
        }
    }

private:

    struct BooleanSummary
    {
        typedef uint32_t Value;
        size_t counts[2];

        BooleanSummary () : counts({0, 0}) {}
        void add (Value value) { ++counts[value]; }
        Value get_mode () const { return counts[1] > counts[0]; }
        size_t get_count (Value value) const { return counts[value]; }
    };

    struct CountSummary
    {
        enum { max_count = 16 };  // assume mode lies in [0, max_count)

        typedef uint32_t Value;
        size_t counts[max_count];

        CountSummary () { std::fill(counts, counts + max_count, 0); }

        void add (uint32_t value)
        {
            if (value < max_count) {
                ++counts[value];
            }
        }

        uint32_t get_mode () const
        {
            uint32_t value = 0;
            for (size_t i = 0; i < max_count; ++i) {
                if (counts[i] > counts[value]) {
                    value = i;
                }
            }
            return value;
        }

        uint32_t get_count (Value value) const
        {
            LOOM_ASSERT_LT(value, max_count);
            return counts[value];
        }
    };

    static protobuf::ProductValue::Observed get_unobserved (
            const ValueSchema & schema)
    {
        protobuf::ProductValue::Observed unobserved;
        unobserved.set_sparsity(ProductValue::Observed::DENSE);
        for (size_t i = 0; i < schema.total_size(); ++i) {
            unobserved.add_dense(false);
        }
        return unobserved;
    }

    template<class Summaries, class Values>
    void tare_type (const Summaries & summaries, Values & values)
    {
        const float count_threshold = config_.tare_threshold() * row_count_;
        for (const auto & summary : summaries) {
            const auto mode = summary.get_mode();
            bool is_dense = (summary.get_count(mode) > count_threshold);
            tare_.mutable_observed()->add_dense(is_dense);
            if (is_dense) {
                values.Add(mode);
            }
        }
    }

    template<class T>
    void sparsify_type (
            size_t begin,
            size_t end,
            const ProductValue & row,
            const ProductValue & tare,
            ProductValue & pos,
            ProductValue & neg) const
    {
        const auto & row_dense = row.observed().dense();
        const auto & tare_dense = tare.observed().dense();
        auto & pos_dense = * pos.mutable_observed()->mutable_dense();
        auto & neg_dense = * neg.mutable_observed()->mutable_dense();

        const auto & row_values = protobuf::Fields<T>::get(row);
        const auto & tare_values = protobuf::Fields<T>::get(tare);
        auto & pos_values = protobuf::Fields<T>::get(pos);
        auto & neg_values = protobuf::Fields<T>::get(neg);

        size_t row_pos = 0;
        size_t tare_pos = 0;
        for (size_t i = begin; i < end; ++i) {
            const bool row_observed = row_dense.Get(i);
            const bool tare_observed = tare_dense.Get(i);
            if (tare_observed) {
                const auto tare_value = tare_values.Get(tare_pos++);
                if (LOOM_LIKELY(row_observed)) {
                    const auto row_value = row_values.Get(row_pos++);
                    if (LOOM_UNLIKELY(row_value != tare_value)) {
                        pos_dense.Set(i, true);
                        pos_values.Add(row_value);
                        neg_dense.Set(i, true);
                        neg_values.Add(tare_value);
                    }
                } else {
                    neg_dense.Set(i, true);
                    neg_values.Add(tare_value);
                }
            } else {
                if (LOOM_UNLIKELY(row_observed)) {
                    const auto row_value = row_values.Get(row_pos++);
                    pos_dense.Set(i, true);
                    pos_values.Add(row_value);
                }
            }
        }
    }

    const protobuf::Config::Sparsify & config_;
    const ValueSchema & schema_;
    const protobuf::ProductValue::Observed unobserved_;
    size_t row_count_;
    std::vector<BooleanSummary> booleans_;
    std::vector<CountSummary> counts_;
    protobuf::ProductValue tare_;
};

} // namespace loom
<|endoftext|>


<commit_before>/*
 *  FDOmenu - Menu code generator for icewm
 *  Copyright (C) 2015 Eduard Bloch
 *
 *  Inspired by icewm-menu-gnome2 and Freedesktop.org specifications
 *  Using pure glib/gio code and a built-in menu structure instead
 *  the XML based external definition (as suggested by FD.o specs)
 *
 *  Release under terms of the GNU Library General Public License
 *  (version 2.0)
 *
 *  2015/02/05: Eduard Bloch <edi@gmx.de>
 *  - initial version
 */

#include "config.h"
#include "base.h"
#include "sysdep.h"
#include "intl.h"

#include <glib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#include <gio/gdesktopappinfo.h>

template<class T>
struct auto_gfree
{
	T *p;
	auto_gfree(T *xp) : p(xp) {};
	~auto_gfree() { g_free(p); }
};

bool find_in_zArray(const char * const *arrToScan, const char *keyword)
{
	for(const gchar * const * p=arrToScan;*p;++p)
		if(!strcmp(keyword, *p))
			return true;
	return false;
}

typedef GList* pglist;

pglist msettings=0, mscreensavers=0, maccessories=0, mdevelopment=0, meducation=0,
		mgames=0, mgraphics=0, mmultimedia=0, mnetwork=0, moffice=0, msystem=0, mother=0;

//#warning needing a dupe filter for filename, maybe use GHashTable for that

void proc_dir(const char *path, unsigned depth=0)
{
	//printf("dir: %s\n", path);

	GDir *pdir = g_dir_open (path, 0, NULL);
	if(!pdir)
		return;

	const gchar *szFilename(NULL);
	while(NULL != (szFilename = g_dir_read_name (pdir)))
	{
		if(!szFilename)
			continue;
		gchar *szFullName = g_strjoin("/", path, szFilename, 0);
		auto_gfree<gchar> xxfree(szFullName);
		static GStatBuf buf;
		if(g_stat(szFullName, &buf))
			return;
		if(S_ISDIR(buf.st_mode))
		{
			static ino_t reclog[6];
			for(unsigned i=0; i<depth; ++i)
			{
				if(reclog[i] == buf.st_ino)
					goto dir_visited_before;
			}
			if(depth<ACOUNT(reclog))
			{
				reclog[++depth] = buf.st_ino;
				proc_dir(szFullName, depth);
				--depth;
			}
			dir_visited_before:;
		}

		if(!S_ISREG(buf.st_mode))
			return;
		//printf("got: %s\n", szFullName);

		GDesktopAppInfo *pInfo = g_desktop_app_info_new_from_filename (szFullName);
		if(!pInfo)
			continue;

		if(!g_app_info_should_show((GAppInfo*) pInfo))
			continue;

		const char *cmdraw = g_app_info_get_commandline ((GAppInfo*) pInfo);
		if(!cmdraw || !*cmdraw)
			continue;

		// let's whitespace all special fields that we don't support
		gchar * cmd = g_strdup(cmdraw);
		auto_gfree<gchar> cmdfree(cmd);
		bool bDelChars=false;
		for(gchar *p=cmd; *p; ++p)
		{
			if('%' == *p)
				bDelChars=true;
			if(bDelChars)
				*p = ' ';
			if(bDelChars && !isprint((unsigned)*p))
				bDelChars=false;
		}

		const char *pName=g_app_info_get_name( (GAppInfo*) pInfo);
		if(!pName)
			continue;
		const char *pCats=g_desktop_app_info_get_categories(pInfo);
		if(!pCats)
			pCats="Other";

		//printf("icon: %s -> %s\n", pName, pCats);

		const char *sicon = "-";
		GIcon *pIcon=g_app_info_get_icon( (GAppInfo*) pInfo);
		if (pIcon)
			sicon = g_icon_to_string(pIcon);
		char *menuLine = g_strdup_printf("# %s -> %s\n"
				"prog \"%s\" %s %s\n",
				szFullName, pCats,
				pName, sicon, cmd);
		//printf("%s", menuLine);

		// pidgeonholing roughly by guessed menu structure
		gchar **ppCats = g_strsplit(pCats, ";", -1);
		if (find_in_zArray(ppCats, "Screensaver"))
			mscreensavers = g_list_append(mscreensavers, menuLine);
		else if (find_in_zArray(ppCats, "Settings"))
			msettings = g_list_append(msettings, menuLine);
		else if (find_in_zArray(ppCats, "Accessories"))
			maccessories = g_list_append(maccessories, menuLine);
		else if (find_in_zArray(ppCats, "Development"))
			mdevelopment = g_list_append(mdevelopment, menuLine);
		else if (find_in_zArray(ppCats, "Education"))
			meducation = g_list_append(meducation, menuLine);
		else if (find_in_zArray(ppCats, "Game"))
			mgames = g_list_append(mgames, menuLine);
		else if (find_in_zArray(ppCats, "Graphics"))
			mgraphics = g_list_append(mgraphics, menuLine);
		else if (find_in_zArray(ppCats, "Audio") || find_in_zArray(ppCats, "Video")
				|| find_in_zArray(ppCats, "AudioVideo"))
		{
			mmultimedia = g_list_append(mmultimedia, menuLine);
		}
		else if (find_in_zArray(ppCats, "Network"))
			mnetwork = g_list_append(mnetwork, menuLine);
		else if (find_in_zArray(ppCats, "Office"))
			moffice = g_list_append(moffice, menuLine);
		else if (find_in_zArray(ppCats, "System") || find_in_zArray(ppCats, "Emulator"))
		{
			msystem = g_list_append(msystem, menuLine);
		}
		else
			mother = g_list_append(mother, menuLine);

		//fprintf(stderr, "jo, %s", menuLine);

	}
	g_dir_close(pdir);
}

void dump_menu()
{

	/*
	for (pglist l =  msettings; l != NULL; l = l->next)
	  {
	    puts((char*) l->data);
	  }
*/

/*
	pglist msettings=0, mscreensavers=0, maccessories=0, mdevelopment=0, meducation=0,
			mgames=0, mgraphics=0, mmultimedia=0, mnetwork=0, moffice=0, msystem=0, mother=0;
			*/
	struct tMenuHead {
		char *title;
		pglist pEntries;
		tMenuHead(char *xt, pglist p) : title(xt), pEntries(p){};
	};
	pglist xmenu = 0;

// XXX: convert to g_list_insert_sorted using a locale based gcomp function

	xmenu = g_list_append(xmenu, new tMenuHead(_("Settings"), msettings));
	xmenu = g_list_append(xmenu, new tMenuHead(_("Screensavers"), mscreensavers));
	xmenu = g_list_append(xmenu, new tMenuHead(_("Accessories"), maccessories));
	xmenu = g_list_append(xmenu, new tMenuHead(_("Development"), mdevelopment));
	xmenu = g_list_append(xmenu, new tMenuHead(_("Education"), meducation));
	xmenu = g_list_append(xmenu, new tMenuHead(_("Games"), mgames));
	xmenu = g_list_append(xmenu, new tMenuHead(_("Graphics"), mgraphics));
	xmenu = g_list_append(xmenu, new tMenuHead(_("Multimedia"), mmultimedia));
	xmenu = g_list_append(xmenu, new tMenuHead(_("Network"), mnetwork));
	xmenu = g_list_append(xmenu, new tMenuHead(_("Office"), moffice));
	xmenu = g_list_append(xmenu, new tMenuHead(_("System"), msystem));
	xmenu = g_list_append(xmenu, new tMenuHead(_("Other"), mother));

	for (pglist l = xmenu; l != NULL; l = l->next)
	{
		printf("menu \"%s\" folder {\n", ((tMenuHead*) l->data)->title);
		for (pglist m = ((tMenuHead*) l->data)->pEntries; m != NULL; m = m->next)
		{
			puts((char*) m->data);
		}
		puts("}\n");
	}

}

int main(int argc, char **) {

	setlocale (LC_ALL, "");

#ifdef ENABLE_NLS
    bindtextdomain(PACKAGE, LOCDIR);
    textdomain(PACKAGE);
#endif

	const char * usershare=getenv("XDG_DATA_HOME"),
			*sysshare=getenv("XDG_DATA_DIRS");

	if(!usershare || !*usershare)
		usershare=g_strjoin(NULL, getenv("HOME"), "/.local/share", NULL);

	if(!sysshare || !*sysshare)
		sysshare="/usr/local/share/:/usr/share/";

	if(argc>1)
	{
		g_fprintf(stderr, "This program doesn't use command line options. It only listens to\n"
			"environment variables defined by XDG Base Directory Specification.\n"
			"XDG_DATA_HOME=%s\n"
				"XDG_DATA_DIRS=%s\n"
			,usershare, sysshare);
		return EXIT_FAILURE;
	}

	proc_dir(usershare);
	gchar **ppDirs = g_strsplit (sysshare, ":", -1);
	for(const gchar * const * p=ppDirs;*p;++p)
		proc_dir(g_strjoin(0, *p, "/applications", 0));

	dump_menu();

	return EXIT_SUCCESS;
}
<commit_msg>Sorting submenues by translateable names<commit_after>/*
 *  FDOmenu - Menu code generator for icewm
 *  Copyright (C) 2015 Eduard Bloch
 *
 *  Inspired by icewm-menu-gnome2 and Freedesktop.org specifications
 *  Using pure glib/gio code and a built-in menu structure instead
 *  the XML based external definition (as suggested by FD.o specs)
 *
 *  Release under terms of the GNU Library General Public License
 *  (version 2.0)
 *
 *  2015/02/05: Eduard Bloch <edi@gmx.de>
 *  - initial version
 */

#include "config.h"
#include "base.h"
#include "sysdep.h"
#include "intl.h"

#include <glib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#include <gio/gdesktopappinfo.h>

template<class T>
struct auto_gfree
{
	T *p;
	auto_gfree(T *xp) : p(xp) {};
	~auto_gfree() { g_free(p); }
};

bool find_in_zArray(const char * const *arrToScan, const char *keyword)
{
	for(const gchar * const * p=arrToScan;*p;++p)
		if(!strcmp(keyword, *p))
			return true;
	return false;
}

typedef GList* pglist;

pglist msettings=0, mscreensavers=0, maccessories=0, mdevelopment=0, meducation=0,
		mgames=0, mgraphics=0, mmultimedia=0, mnetwork=0, moffice=0, msystem=0, mother=0;

//#warning needing a dupe filter for filename, maybe use GHashTable for that

void proc_dir(const char *path, unsigned depth=0)
{
	GDir *pdir = g_dir_open (path, 0, NULL);
	if(!pdir)
		return;

	const gchar *szFilename(NULL);
	while(NULL != (szFilename = g_dir_read_name (pdir)))
	{
		if(!szFilename)
			continue;
		gchar *szFullName = g_strjoin("/", path, szFilename, NULL);
		auto_gfree<gchar> xxfree(szFullName);
		static GStatBuf buf;
		if(g_stat(szFullName, &buf))
			return;
		if(S_ISDIR(buf.st_mode))
		{
			static ino_t reclog[6];
			for(unsigned i=0; i<depth; ++i)
			{
				if(reclog[i] == buf.st_ino)
					goto dir_visited_before;
			}
			if(depth<ACOUNT(reclog))
			{
				reclog[++depth] = buf.st_ino;
				proc_dir(szFullName, depth);
				--depth;
			}
			dir_visited_before:;
		}

		if(!S_ISREG(buf.st_mode))
			return;

		GDesktopAppInfo *pInfo = g_desktop_app_info_new_from_filename (szFullName);
		if(!pInfo)
			continue;

		if(!g_app_info_should_show((GAppInfo*) pInfo))
			continue;

		const char *cmdraw = g_app_info_get_commandline ((GAppInfo*) pInfo);
		if(!cmdraw || !*cmdraw)
			continue;

		// let's whitespace all special fields that we don't support
		gchar * cmd = g_strdup(cmdraw);
		auto_gfree<gchar> cmdfree(cmd);
		bool bDelChars=false;
		for(gchar *p=cmd; *p; ++p)
		{
			if('%' == *p)
				bDelChars=true;
			if(bDelChars)
				*p = ' ';
			if(bDelChars && !isprint((unsigned)*p))
				bDelChars=false;
		}

		const char *pName=g_app_info_get_name( (GAppInfo*) pInfo);
		if(!pName)
			continue;
		const char *pCats=g_desktop_app_info_get_categories(pInfo);
		if(!pCats)
			pCats="Other";

		const char *sicon = "-";
		GIcon *pIcon=g_app_info_get_icon( (GAppInfo*) pInfo);
		if (pIcon)
			sicon = g_icon_to_string(pIcon);
		char *menuLine = g_strdup_printf(
				//"# %s -> %s\n"
				"prog \"%s\" %s %s\n",
				//szFullName, pCats,
				pName, sicon, cmd);

		// Pigeonholing roughly by guessed menu structure
		gchar **ppCats = g_strsplit(pCats, ";", -1);
		if (find_in_zArray(ppCats, "Screensaver"))
			mscreensavers = g_list_append(mscreensavers, menuLine);
		else if (find_in_zArray(ppCats, "Settings"))
			msettings = g_list_append(msettings, menuLine);
		else if (find_in_zArray(ppCats, "Accessories"))
			maccessories = g_list_append(maccessories, menuLine);
		else if (find_in_zArray(ppCats, "Development"))
			mdevelopment = g_list_append(mdevelopment, menuLine);
		else if (find_in_zArray(ppCats, "Education"))
			meducation = g_list_append(meducation, menuLine);
		else if (find_in_zArray(ppCats, "Game"))
			mgames = g_list_append(mgames, menuLine);
		else if (find_in_zArray(ppCats, "Graphics"))
			mgraphics = g_list_append(mgraphics, menuLine);
		else if (find_in_zArray(ppCats, "AudioVideo") || find_in_zArray(ppCats, "Audio")
				|| find_in_zArray(ppCats, "Video"))
		{
			mmultimedia = g_list_append(mmultimedia, menuLine);
		}
		else if (find_in_zArray(ppCats, "Network"))
			mnetwork = g_list_append(mnetwork, menuLine);
		else if (find_in_zArray(ppCats, "Office"))
			moffice = g_list_append(moffice, menuLine);
		else if (find_in_zArray(ppCats, "System") || find_in_zArray(ppCats, "Emulator"))
			msystem = g_list_append(msystem, menuLine);
		else
			mother = g_list_append(mother, menuLine);

	}
	g_dir_close(pdir);
}

struct tMenuHead {
		char *title;
		pglist pEntries;
		tMenuHead(char *xt, pglist p) : title(xt), pEntries(p) {};
	};
gint menu_name_compare(gconstpointer a, gconstpointer b)
{
	tMenuHead *pa=(tMenuHead*)a;
	tMenuHead *pb=(tMenuHead*)b;
	return g_utf8_collate(pa->title, pb->title);
}

void print_submenu(gpointer l)
{
	printf("menu \"%s\" folder {\n",
					((tMenuHead*) l)->title);
			for (pglist m = ((tMenuHead*) l)->pEntries; m != NULL; m = m->next)
			{
				printf("%s", (const char*) m->data);
	// let the OS cleanup...		g_free(m->data);
			}
			printf("}\n");
}

void dump_menu()
{
	pglist xmenu = 0;
#define	addmenu(name, store) \
		xmenu = g_list_insert_sorted(xmenu, new tMenuHead(name, store),\
				(GCompareFunc)menu_name_compare);
	addmenu(_("Settings"), msettings);
	addmenu(_("Screensavers"), mscreensavers);
	addmenu(_("Accessories"), maccessories);
	addmenu(_("Development"), mdevelopment);
	addmenu(_("Education"), meducation);
	addmenu(_("Games"), mgames);
	addmenu(_("Graphics"), mgraphics);
	addmenu(_("Multimedia"), mmultimedia);
	addmenu(_("Network"), mnetwork);
	addmenu(_("Office"), moffice);
	addmenu(_("System"), msystem);

	for (pglist l = xmenu; l != NULL; l = l->next)
		print_submenu(l->data);
	puts("separator");
	print_submenu(new tMenuHead(_("Other"), mother));

}

int main(int argc, char **) {

	setlocale (LC_ALL, "");

#ifdef ENABLE_NLS
    bindtextdomain(PACKAGE, LOCDIR);
    textdomain(PACKAGE);
#endif

	const char * usershare=getenv("XDG_DATA_HOME"),
			*sysshare=getenv("XDG_DATA_DIRS");

	if(!usershare || !*usershare)
		usershare=g_strjoin(NULL, getenv("HOME"), "/.local/share", NULL);

	if(!sysshare || !*sysshare)
		sysshare="/usr/local/share/:/usr/share/";

	if(argc>1)
	{
		g_fprintf(stderr, "This program doesn't use command line options. It only listens to\n"
			"environment variables defined by XDG Base Directory Specification.\n"
			"XDG_DATA_HOME=%s\n"
				"XDG_DATA_DIRS=%s\n"
			,usershare, sysshare);
		return EXIT_FAILURE;
	}

	proc_dir(usershare);
	gchar **ppDirs = g_strsplit (sysshare, ":", -1);
	for(const gchar * const * p=ppDirs;*p;++p)
		proc_dir(g_strjoin(0, *p, "/applications", NULL));

	dump_menu();

	return EXIT_SUCCESS;
}
<|endoftext|>