<commit_before>#include "CodeGen_OpenCL_Dev.h"
#include "Debug.h"

// TODO: This needs a runtime controlled switch based on the device extension
// string.
//#define ENABLE_CL_KHR_FP64

namespace Halide {
namespace Internal {

using std::ostringstream;
using std::string;
using std::vector;

static ostringstream nil;

CodeGen_OpenCL_Dev::CodeGen_OpenCL_Dev() {
    clc = new CodeGen_OpenCL_C(src_stream);
}

string CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::print_type(Type type) {
    ostringstream oss;
    assert(type.width == 1 && "Can't codegen vector types to OpenCL C (yet)");
    if (type.is_float()) {
        if (type.bits == 16) {
            oss << "half";
        } else if (type.bits == 32) {
            oss << "float";
        } else if (type.bits == 64) {
            oss << "double";
        } else {
            assert(false && "Can't represent a float with this many bits in OpenCL C");
        }

    } else {
        if (type.is_uint() && type.bits > 1) oss << 'u';
        switch (type.bits) {
        case 1:
            oss << "bool";
            break;
        case 8:
            oss << "char";
            break;
        case 16:
            oss << "short";
            break;
        case 32:
            oss << "int";
            break;
        case 64:
            oss << "long";
            break;
        default:
            assert(false && "Can't represent an integer with this many bits in OpenCL C");
        }
    }
    return oss.str();
}

namespace {
Expr simt_intrinsic(const string &name) {
    if (ends_with(name, ".threadidx")) {
        return Call::make(Int(32), "get_local_id", vec(Expr(0)), Call::Extern);
    } else if (ends_with(name, ".threadidy")) {
        return Call::make(Int(32), "get_local_id", vec(Expr(1)), Call::Extern);
    } else if (ends_with(name, ".threadidz")) {
        return Call::make(Int(32), "get_local_id", vec(Expr(2)), Call::Extern);
    } else if (ends_with(name, ".threadidw")) {
        return Call::make(Int(32), "get_local_id", vec(Expr(3)), Call::Extern);
    } else if (ends_with(name, ".blockidx")) {
        return Call::make(Int(32), "get_group_id", vec(Expr(0)), Call::Extern);
    } else if (ends_with(name, ".blockidy")) {
        return Call::make(Int(32), "get_group_id", vec(Expr(1)), Call::Extern);
    } else if (ends_with(name, ".blockidz")) {
        return Call::make(Int(32), "get_group_id", vec(Expr(2)), Call::Extern);
    } else if (ends_with(name, ".blockidw")) {
        return Call::make(Int(32), "get_group_id", vec(Expr(3)), Call::Extern);
    }
    assert(false && "simt_intrinsic called on bad variable name");
    return Expr();
}
}

void CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::visit(const For *loop) {
    if (is_gpu_var(loop->name)) {
        debug(0) << "Dropping loop " << loop->name << " (" << loop->min << ", " << loop->extent << ")\n";
        assert(loop->for_type == For::Parallel && "kernel loop must be parallel");

        Expr simt_idx = simt_intrinsic(loop->name);
        Expr loop_var = Add::make(loop->min, simt_idx);
        Expr cond = LT::make(simt_idx, loop->extent);
        debug(0) << "for -> if (" << cond << ")\n";

        string id_idx = print_expr(simt_idx);
        string id_cond = print_expr(cond);

        do_indent();
        stream << "if (" << id_cond << ")\n";

        open_scope();
        do_indent();
        stream << print_type(Int(32)) << " " << print_name(loop->name) << " = " << id_idx << ";\n";
        loop->body.accept(this);
        close_scope("for " + id_cond);

    } else {
    	assert(loop->for_type != For::Parallel && "Cannot emit parallel loops in OpenCL C");
    	CodeGen_C::visit(loop);
    }
}

void CodeGen_OpenCL_Dev::add_kernel(Stmt s, string name, const vector<Argument> &args) {
    debug(0) << "hi CodeGen_OpenCL_Dev::compile! " << name << "\n";

    // TODO: do we have to uniquify these names, or can we trust that they are safe?
    cur_kernel_name = name;
    clc->add_kernel(s, name, args);
}

namespace {
const string kernel_preamble = "";
}

void CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::add_kernel(Stmt s, string name, const vector<Argument> &args) {
    debug(0) << "hi! " << name << "\n";

    stream << kernel_preamble;

    // Emit the function prototype
    stream << "__kernel void " << name << "(\n";
    for (size_t i = 0; i < args.size(); i++) {
        if (args[i].is_buffer) {
            stream << " __global " << print_type(args[i].type) << " *"
                   << print_name(args[i].name);
        } else {
            stream << " const "
                   << print_type(args[i].type)
                   << " "
                   << print_name(args[i].name);
        }

        if (i < args.size()-1) stream << ",\n";
    }
    stream << ",\n" << "__local uchar* shared";

    stream << ") {\n";

    print(s);

    stream << "}\n";
}

void CodeGen_OpenCL_Dev::init_module() {
    debug(0) << "OpenCL device codegen init_module\n";

    // wipe the internal kernel source
    src_stream.str("");
    src_stream.clear();

    // This identifies the program as OpenCL C (as opposed to SPIR).
    src_stream << "/*OpenCL C*/\n";

#ifdef ENABLE_CL_KHR_FP64
    src_stream << "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
#endif
    src_stream << "#pragma OPENCL FP_CONTRACT ON\n";

    // Write out the Halide math functions.
    src_stream << "float nan_f32() { return NAN; }\n"
               << "float neg_inf_f32() { return -INFINITY; }\n"
               << "float inf_f32() { return INFINITY; }\n"
               << "float float_from_bits(unsigned int x) {return as_float(x);}\n"
               << "float sqrt_f32(float x) { return sqrt(x); }\n"
               << "float sin_f32(float x) { return sin(x); }\n"
               << "float cos_f32(float x) { return cos(x); }\n"
               << "float exp_f32(float x) { return exp(x); }\n"
               << "float log_f32(float x) { return log(x); }\n"
               << "float abs_f32(float x) { return fabs(x); }\n"
               << "float floor_f32(float x) { return floor(x); }\n"
               << "float ceil_f32(float x) { return ceil(x); }\n"
               << "float round_f32(float x) { return round(x); }\n"
               << "float pow_f32(float x, float y) { return pow(x, y); }\n"
               << "float asin_f32(float x) { return asin(x); }\n"
               << "float acos_f32(float x) { return acos(x); }\n"
               << "float tan_f32(float x) { return tan(x); }\n"
               << "float atan_f32(float x) { return atan(x); }\n"
               << "float atan2_f32(float y, float x) { return atan2(y, x); }\n"
               << "float sinh_f32(float x) { return sinh(x); }\n"
               << "float asinh_f32(float x) { return asinh(x); }\n"
               << "float cosh_f32(float x) { return cosh(x); }\n"
               << "float acosh_f32(float x) { return acosh(x); }\n"
               << "float tanh_f32(float x) { return tanh(x); }\n"
               << "float atanh_f32(float x) { return atanh(x); }\n";

#ifdef ENABLE_CL_KHR_FP64
    src_stream << "double sqrt_f64(double x) { return sqrt(x); }\n"
               << "double sin_f64(double x) { return sin(x); }\n"
               << "double cos_f64(double x) { return cos(x); }\n"
               << "double exp_f64(double x) { return exp(x); }\n"
               << "double log_f64(double x) { return log(x); }\n"
               << "double abs_f64(double x) { return fabs(x); }\n"
               << "double floor_f64(double x) { return floor(x); }\n"
               << "double ceil_f64(double x) { return ceil(x); }\n"
               << "double round_f64(double x) { return round(x); }\n"
               << "double pow_f64(double x, double y) { return pow(x, y); }\n"
               << "double asin_f64(double x) { return asin(x); }\n"
               << "double acos_f64(double x) { return acos(x); }\n"
               << "double tan_f64(double x) { return tan(x); }\n"
               << "double atan_f64(double x) { return atan(x); }\n"
               << "double atan2_f64(double y, double x) { return atan2(y, x); }\n"
               << "double sinh_f64(double x) { return sinh(x); }\n"
               << "double asinh_f64(double x) { return asinh(x); }\n"
               << "double cosh_f64(double x) { return cosh(x); }\n"
               << "double acosh_f64(double x) { return acosh(x); }\n"
               << "double tanh_f64(double x) { return tanh(x); }\n"
               << "double atanh_f64(double x) { return atanh(x); }\n";
#endif

    src_stream << '\n';

    // Add at least one kernel to avoid errors on some implementations for functions
    // without any GPU schedules.
    src_stream << "__kernel void _at_least_one_kernel(int x) { }\n";

    cur_kernel_name = "";
}

vector<char> CodeGen_OpenCL_Dev::compile_to_src() {
    string str = src_stream.str();
    vector<char> buffer(str.begin(), str.end());
    buffer.push_back(0);
    std::cout << str << "\n";
    return buffer;
}

string CodeGen_OpenCL_Dev::get_current_kernel_name() {
    return cur_kernel_name;
}

void CodeGen_OpenCL_Dev::dump() {
    std::cerr << src_stream.str() << std::endl;
}

}}
<commit_msg>Removed code dump from compile_to_src<commit_after>#include "CodeGen_OpenCL_Dev.h"
#include "Debug.h"

// TODO: This needs a runtime controlled switch based on the device extension
// string.
//#define ENABLE_CL_KHR_FP64

namespace Halide {
namespace Internal {

using std::ostringstream;
using std::string;
using std::vector;

static ostringstream nil;

CodeGen_OpenCL_Dev::CodeGen_OpenCL_Dev() {
    clc = new CodeGen_OpenCL_C(src_stream);
}

string CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::print_type(Type type) {
    ostringstream oss;
    assert(type.width == 1 && "Can't codegen vector types to OpenCL C (yet)");
    if (type.is_float()) {
        if (type.bits == 16) {
            oss << "half";
        } else if (type.bits == 32) {
            oss << "float";
        } else if (type.bits == 64) {
            oss << "double";
        } else {
            assert(false && "Can't represent a float with this many bits in OpenCL C");
        }

    } else {
        if (type.is_uint() && type.bits > 1) oss << 'u';
        switch (type.bits) {
        case 1:
            oss << "bool";
            break;
        case 8:
            oss << "char";
            break;
        case 16:
            oss << "short";
            break;
        case 32:
            oss << "int";
            break;
        case 64:
            oss << "long";
            break;
        default:
            assert(false && "Can't represent an integer with this many bits in OpenCL C");
        }
    }
    return oss.str();
}

namespace {
Expr simt_intrinsic(const string &name) {
    if (ends_with(name, ".threadidx")) {
        return Call::make(Int(32), "get_local_id", vec(Expr(0)), Call::Extern);
    } else if (ends_with(name, ".threadidy")) {
        return Call::make(Int(32), "get_local_id", vec(Expr(1)), Call::Extern);
    } else if (ends_with(name, ".threadidz")) {
        return Call::make(Int(32), "get_local_id", vec(Expr(2)), Call::Extern);
    } else if (ends_with(name, ".threadidw")) {
        return Call::make(Int(32), "get_local_id", vec(Expr(3)), Call::Extern);
    } else if (ends_with(name, ".blockidx")) {
        return Call::make(Int(32), "get_group_id", vec(Expr(0)), Call::Extern);
    } else if (ends_with(name, ".blockidy")) {
        return Call::make(Int(32), "get_group_id", vec(Expr(1)), Call::Extern);
    } else if (ends_with(name, ".blockidz")) {
        return Call::make(Int(32), "get_group_id", vec(Expr(2)), Call::Extern);
    } else if (ends_with(name, ".blockidw")) {
        return Call::make(Int(32), "get_group_id", vec(Expr(3)), Call::Extern);
    }
    assert(false && "simt_intrinsic called on bad variable name");
    return Expr();
}
}

void CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::visit(const For *loop) {
    if (is_gpu_var(loop->name)) {
        debug(0) << "Dropping loop " << loop->name << " (" << loop->min << ", " << loop->extent << ")\n";
        assert(loop->for_type == For::Parallel && "kernel loop must be parallel");

        Expr simt_idx = simt_intrinsic(loop->name);
        Expr loop_var = Add::make(loop->min, simt_idx);
        Expr cond = LT::make(simt_idx, loop->extent);
        debug(0) << "for -> if (" << cond << ")\n";

        string id_idx = print_expr(simt_idx);
        string id_cond = print_expr(cond);

        do_indent();
        stream << "if (" << id_cond << ")\n";

        open_scope();
        do_indent();
        stream << print_type(Int(32)) << " " << print_name(loop->name) << " = " << id_idx << ";\n";
        loop->body.accept(this);
        close_scope("for " + id_cond);

    } else {
    	assert(loop->for_type != For::Parallel && "Cannot emit parallel loops in OpenCL C");
    	CodeGen_C::visit(loop);
    }
}

void CodeGen_OpenCL_Dev::add_kernel(Stmt s, string name, const vector<Argument> &args) {
    debug(0) << "hi CodeGen_OpenCL_Dev::compile! " << name << "\n";

    // TODO: do we have to uniquify these names, or can we trust that they are safe?
    cur_kernel_name = name;
    clc->add_kernel(s, name, args);
}

namespace {
const string kernel_preamble = "";
}

void CodeGen_OpenCL_Dev::CodeGen_OpenCL_C::add_kernel(Stmt s, string name, const vector<Argument> &args) {
    debug(0) << "hi! " << name << "\n";

    stream << kernel_preamble;

    // Emit the function prototype
    stream << "__kernel void " << name << "(\n";
    for (size_t i = 0; i < args.size(); i++) {
        if (args[i].is_buffer) {
            stream << " __global " << print_type(args[i].type) << " *"
                   << print_name(args[i].name);
        } else {
            stream << " const "
                   << print_type(args[i].type)
                   << " "
                   << print_name(args[i].name);
        }

        if (i < args.size()-1) stream << ",\n";
    }
    stream << ",\n" << "__local uchar* shared";

    stream << ") {\n";

    print(s);

    stream << "}\n";
}

void CodeGen_OpenCL_Dev::init_module() {
    debug(0) << "OpenCL device codegen init_module\n";

    // wipe the internal kernel source
    src_stream.str("");
    src_stream.clear();

    // This identifies the program as OpenCL C (as opposed to SPIR).
    src_stream << "/*OpenCL C*/\n";

#ifdef ENABLE_CL_KHR_FP64
    src_stream << "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
#endif
    src_stream << "#pragma OPENCL FP_CONTRACT ON\n";

    // Write out the Halide math functions.
    src_stream << "float nan_f32() { return NAN; }\n"
               << "float neg_inf_f32() { return -INFINITY; }\n"
               << "float inf_f32() { return INFINITY; }\n"
               << "float float_from_bits(unsigned int x) {return as_float(x);}\n"
               << "float sqrt_f32(float x) { return sqrt(x); }\n"
               << "float sin_f32(float x) { return sin(x); }\n"
               << "float cos_f32(float x) { return cos(x); }\n"
               << "float exp_f32(float x) { return exp(x); }\n"
               << "float log_f32(float x) { return log(x); }\n"
               << "float abs_f32(float x) { return fabs(x); }\n"
               << "float floor_f32(float x) { return floor(x); }\n"
               << "float ceil_f32(float x) { return ceil(x); }\n"
               << "float round_f32(float x) { return round(x); }\n"
               << "float pow_f32(float x, float y) { return pow(x, y); }\n"
               << "float asin_f32(float x) { return asin(x); }\n"
               << "float acos_f32(float x) { return acos(x); }\n"
               << "float tan_f32(float x) { return tan(x); }\n"
               << "float atan_f32(float x) { return atan(x); }\n"
               << "float atan2_f32(float y, float x) { return atan2(y, x); }\n"
               << "float sinh_f32(float x) { return sinh(x); }\n"
               << "float asinh_f32(float x) { return asinh(x); }\n"
               << "float cosh_f32(float x) { return cosh(x); }\n"
               << "float acosh_f32(float x) { return acosh(x); }\n"
               << "float tanh_f32(float x) { return tanh(x); }\n"
               << "float atanh_f32(float x) { return atanh(x); }\n";

#ifdef ENABLE_CL_KHR_FP64
    src_stream << "double sqrt_f64(double x) { return sqrt(x); }\n"
               << "double sin_f64(double x) { return sin(x); }\n"
               << "double cos_f64(double x) { return cos(x); }\n"
               << "double exp_f64(double x) { return exp(x); }\n"
               << "double log_f64(double x) { return log(x); }\n"
               << "double abs_f64(double x) { return fabs(x); }\n"
               << "double floor_f64(double x) { return floor(x); }\n"
               << "double ceil_f64(double x) { return ceil(x); }\n"
               << "double round_f64(double x) { return round(x); }\n"
               << "double pow_f64(double x, double y) { return pow(x, y); }\n"
               << "double asin_f64(double x) { return asin(x); }\n"
               << "double acos_f64(double x) { return acos(x); }\n"
               << "double tan_f64(double x) { return tan(x); }\n"
               << "double atan_f64(double x) { return atan(x); }\n"
               << "double atan2_f64(double y, double x) { return atan2(y, x); }\n"
               << "double sinh_f64(double x) { return sinh(x); }\n"
               << "double asinh_f64(double x) { return asinh(x); }\n"
               << "double cosh_f64(double x) { return cosh(x); }\n"
               << "double acosh_f64(double x) { return acosh(x); }\n"
               << "double tanh_f64(double x) { return tanh(x); }\n"
               << "double atanh_f64(double x) { return atanh(x); }\n";
#endif

    src_stream << '\n';

    // Add at least one kernel to avoid errors on some implementations for functions
    // without any GPU schedules.
    src_stream << "__kernel void _at_least_one_kernel(int x) { }\n";

    cur_kernel_name = "";
}

vector<char> CodeGen_OpenCL_Dev::compile_to_src() {
    string str = src_stream.str();
    vector<char> buffer(str.begin(), str.end());
    buffer.push_back(0);
    return buffer;
}

string CodeGen_OpenCL_Dev::get_current_kernel_name() {
    return cur_kernel_name;
}

void CodeGen_OpenCL_Dev::dump() {
    std::cerr << src_stream.str() << std::endl;
}

}}
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkColor.h"
#include "SkPaint.h"
#include "SkPicture.h"
#include "SkPoint.h"
#include "SkRandom.h"
#include "SkRect.h"
#include "SkString.h"

class PictureRecordBench : public SkBenchmark {
public:
    PictureRecordBench(void* param, const char name[]) : INHERITED(param) {
        fName.printf("picture_record_%s", name);
        fPictureWidth = SkIntToScalar(PICTURE_WIDTH);
        fPictureHeight = SkIntToScalar(PICTURE_HEIGHT);
    }

    enum {
        N = SkBENCHLOOP(25), // number of times to create the picture
        PICTURE_WIDTH = 1000,
        PICTURE_HEIGHT = 4000,
    };
protected:
    virtual const char* onGetName() {
        return fName.c_str();
    }

    virtual void onDraw(SkCanvas*) {
        int n = (int)(N * this->innerLoopScale());
        n = SkMax32(1, n);

        for (int i = 0; i < n; i++) {

            SkPicture picture;

            SkCanvas* pCanvas = picture.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
            recordCanvas(pCanvas);

            // we don't need to draw the picture as the endRecording step will
            // do the work of transferring the recorded content into a playback
            // object.
            picture.endRecording();
        }
    }

    virtual void recordCanvas(SkCanvas* canvas) = 0;
    virtual float innerLoopScale() const { return 1; }

    SkString fName;
    SkScalar fPictureWidth;
    SkScalar fPictureHeight;
    SkScalar fTextSize;
private:
    typedef SkBenchmark INHERITED;
};

/*
 *  An SkPicture has internal dictionaries to store bitmaps, matrices, paints,
 *  and regions.  This bench populates those dictionaries to test the speed of
 *  reading and writing to those particular dictionary data structures.
 */
class DictionaryRecordBench : public PictureRecordBench {
public:
    DictionaryRecordBench(void* param)
        : INHERITED(param, "dictionaries") { }

    enum {
        M = SkBENCHLOOP(100),   // number of elements in each dictionary
    };
protected:
    virtual void recordCanvas(SkCanvas* canvas) {

        const SkPoint translateDelta = getTranslateDelta();

        for (int i = 0; i < M; i++) {

            SkColor color = SK_ColorYELLOW + (i % 255);
            SkIRect rect = SkIRect::MakeWH(i,i);

            canvas->save();

            // set the clip to the given region
            SkRegion region;
            region.setRect(rect);
            canvas->clipRegion(region);

            // fill the clip with a color
            SkPaint paint;
            paint.setColor(color);
            canvas->drawPaint(paint);

            // set a matrix on the canvas
            SkMatrix matrix;
            matrix.setRotate(SkIntToScalar(i % 360));
            canvas->setMatrix(matrix);

            // create a simple bitmap
            SkBitmap bitmap;
            bitmap.setConfig(SkBitmap::kRGB_565_Config, 10, 10);
            bitmap.allocPixels();

            // draw a single color into the bitmap
            SkCanvas bitmapCanvas(bitmap);
            bitmapCanvas.drawColor(SkColorSetA(color, i % 255));

            // draw the bitmap onto the canvas
            canvas->drawBitmapMatrix(bitmap, matrix);

            canvas->restore();
            canvas->translate(translateDelta.fX, translateDelta.fY);
        }
    }

    SkPoint getTranslateDelta() {
        SkIPoint canvasSize = onGetSize();
        return SkPoint::Make(SkIntToScalar((PICTURE_WIDTH - canvasSize.fX)/M),
                             SkIntToScalar((PICTURE_HEIGHT- canvasSize.fY)/M));
    }
private:
    typedef PictureRecordBench INHERITED;
};

/*
 *  Populates the SkPaint dictionary with a large number of unique paint
 *  objects that differ only by color
 */
class UniquePaintDictionaryRecordBench : public PictureRecordBench {
public:
    UniquePaintDictionaryRecordBench(void* param)
        : INHERITED(param, "unique_paint_dictionary") { }

    enum {
        M = SkBENCHLOOP(15000),   // number of unique paint objects
    };
protected:
    virtual float innerLoopScale() const SK_OVERRIDE { return 0.1f; }
    virtual void recordCanvas(SkCanvas* canvas) {
        SkRandom rand;
        for (int i = 0; i < M; i++) {
            SkPaint paint;
            paint.setColor(rand.nextU());
            canvas->drawPaint(paint);
        }
    }

private:
    typedef PictureRecordBench INHERITED;
};

/*
 *  Populates the SkPaint dictionary with a number of unique paint
 *  objects that get reused repeatedly
 */
class RecurringPaintDictionaryRecordBench : public PictureRecordBench {
public:
    RecurringPaintDictionaryRecordBench(void* param)
        : INHERITED(param, "recurring_paint_dictionary") { }

    enum {
        ObjCount = 100,           // number of unique paint objects
        M = SkBENCHLOOP(50000),   // number of draw iterations
    };
protected:
    virtual float innerLoopScale() const SK_OVERRIDE { return 0.1f; }
    virtual void recordCanvas(SkCanvas* canvas) {

        for (int i = 0; i < M; i++) {
            SkPaint paint;
            paint.setColor(i % ObjCount);
            canvas->drawPaint(paint);
        }
    }

private:
    typedef PictureRecordBench INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

static SkBenchmark* Fact0(void* p) { return new DictionaryRecordBench(p); }
static SkBenchmark* Fact1(void* p) { return new UniquePaintDictionaryRecordBench(p); }
static SkBenchmark* Fact2(void* p) { return new RecurringPaintDictionaryRecordBench(p); }

static BenchRegistry gReg0(Fact0);
static BenchRegistry gReg1(Fact1);
static BenchRegistry gReg2(Fact2);
<commit_msg>Mark picture record benches as non-rendering.<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkColor.h"
#include "SkPaint.h"
#include "SkPicture.h"
#include "SkPoint.h"
#include "SkRandom.h"
#include "SkRect.h"
#include "SkString.h"

class PictureRecordBench : public SkBenchmark {
public:
    PictureRecordBench(void* param, const char name[]) : INHERITED(param) {
        fName.printf("picture_record_%s", name);
        fPictureWidth = SkIntToScalar(PICTURE_WIDTH);
        fPictureHeight = SkIntToScalar(PICTURE_HEIGHT);
        fIsRendering = false;
    }

    enum {
        N = SkBENCHLOOP(25), // number of times to create the picture
        PICTURE_WIDTH = 1000,
        PICTURE_HEIGHT = 4000,
    };
protected:
    virtual const char* onGetName() {
        return fName.c_str();
    }

    virtual void onDraw(SkCanvas*) {
        int n = (int)(N * this->innerLoopScale());
        n = SkMax32(1, n);

        for (int i = 0; i < n; i++) {

            SkPicture picture;

            SkCanvas* pCanvas = picture.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
            recordCanvas(pCanvas);

            // we don't need to draw the picture as the endRecording step will
            // do the work of transferring the recorded content into a playback
            // object.
            picture.endRecording();
        }
    }

    virtual void recordCanvas(SkCanvas* canvas) = 0;
    virtual float innerLoopScale() const { return 1; }

    SkString fName;
    SkScalar fPictureWidth;
    SkScalar fPictureHeight;
    SkScalar fTextSize;
private:
    typedef SkBenchmark INHERITED;
};

/*
 *  An SkPicture has internal dictionaries to store bitmaps, matrices, paints,
 *  and regions.  This bench populates those dictionaries to test the speed of
 *  reading and writing to those particular dictionary data structures.
 */
class DictionaryRecordBench : public PictureRecordBench {
public:
    DictionaryRecordBench(void* param)
        : INHERITED(param, "dictionaries") { }

    enum {
        M = SkBENCHLOOP(100),   // number of elements in each dictionary
    };
protected:
    virtual void recordCanvas(SkCanvas* canvas) {

        const SkPoint translateDelta = getTranslateDelta();

        for (int i = 0; i < M; i++) {

            SkColor color = SK_ColorYELLOW + (i % 255);
            SkIRect rect = SkIRect::MakeWH(i,i);

            canvas->save();

            // set the clip to the given region
            SkRegion region;
            region.setRect(rect);
            canvas->clipRegion(region);

            // fill the clip with a color
            SkPaint paint;
            paint.setColor(color);
            canvas->drawPaint(paint);

            // set a matrix on the canvas
            SkMatrix matrix;
            matrix.setRotate(SkIntToScalar(i % 360));
            canvas->setMatrix(matrix);

            // create a simple bitmap
            SkBitmap bitmap;
            bitmap.setConfig(SkBitmap::kRGB_565_Config, 10, 10);
            bitmap.allocPixels();

            // draw a single color into the bitmap
            SkCanvas bitmapCanvas(bitmap);
            bitmapCanvas.drawColor(SkColorSetA(color, i % 255));

            // draw the bitmap onto the canvas
            canvas->drawBitmapMatrix(bitmap, matrix);

            canvas->restore();
            canvas->translate(translateDelta.fX, translateDelta.fY);
        }
    }

    SkPoint getTranslateDelta() {
        SkIPoint canvasSize = onGetSize();
        return SkPoint::Make(SkIntToScalar((PICTURE_WIDTH - canvasSize.fX)/M),
                             SkIntToScalar((PICTURE_HEIGHT- canvasSize.fY)/M));
    }
private:
    typedef PictureRecordBench INHERITED;
};

/*
 *  Populates the SkPaint dictionary with a large number of unique paint
 *  objects that differ only by color
 */
class UniquePaintDictionaryRecordBench : public PictureRecordBench {
public:
    UniquePaintDictionaryRecordBench(void* param)
        : INHERITED(param, "unique_paint_dictionary") { }

    enum {
        M = SkBENCHLOOP(15000),   // number of unique paint objects
    };
protected:
    virtual float innerLoopScale() const SK_OVERRIDE { return 0.1f; }
    virtual void recordCanvas(SkCanvas* canvas) {
        SkRandom rand;
        for (int i = 0; i < M; i++) {
            SkPaint paint;
            paint.setColor(rand.nextU());
            canvas->drawPaint(paint);
        }
    }

private:
    typedef PictureRecordBench INHERITED;
};

/*
 *  Populates the SkPaint dictionary with a number of unique paint
 *  objects that get reused repeatedly
 */
class RecurringPaintDictionaryRecordBench : public PictureRecordBench {
public:
    RecurringPaintDictionaryRecordBench(void* param)
        : INHERITED(param, "recurring_paint_dictionary") { }

    enum {
        ObjCount = 100,           // number of unique paint objects
        M = SkBENCHLOOP(50000),   // number of draw iterations
    };
protected:
    virtual float innerLoopScale() const SK_OVERRIDE { return 0.1f; }
    virtual void recordCanvas(SkCanvas* canvas) {

        for (int i = 0; i < M; i++) {
            SkPaint paint;
            paint.setColor(i % ObjCount);
            canvas->drawPaint(paint);
        }
    }

private:
    typedef PictureRecordBench INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

static SkBenchmark* Fact0(void* p) { return new DictionaryRecordBench(p); }
static SkBenchmark* Fact1(void* p) { return new UniquePaintDictionaryRecordBench(p); }
static SkBenchmark* Fact2(void* p) { return new RecurringPaintDictionaryRecordBench(p); }

static BenchRegistry gReg0(Fact0);
static BenchRegistry gReg1(Fact1);
static BenchRegistry gReg2(Fact2);
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */

#include <iostream>
#include <string>
#include <set>
#include <vector>
#include <map>
#include "hal.h"
#include "halBlockMapper.h"

using namespace hal;
using namespace std;

hal_size_t BlockMapper::_maxAdjScan = 5;

BlockMapper::BlockMapper()
{

}

BlockMapper::~BlockMapper()
{
  erase();
}

void BlockMapper::erase()
{
  for (SegMap::iterator i = _segMap.begin(); i != _segMap.end(); ++i)
  {
    delete i->second;
  }
  _segMap.clear();
}

void BlockMapper::init(const Genome* refGenome, const Genome* queryGenome,
                       hal_index_t absRefFirst, hal_index_t absRefLast,
                       bool doDupes)
{
  erase();
  _absRefFirst = absRefFirst;
  _absRefLast = absRefLast;
  _doDupes = doDupes;
  _refGenome = refGenome;
  _refSequence = refGenome->getSequenceBySite(_absRefFirst);
  assert(_refSequence == refGenome->getSequenceBySite(_absRefLast));
  _queryGenome = queryGenome;

  if (queryGenome->getParent() == refGenome)
  {
    _rel = RefParent;
    _queryChildIndex = refGenome->getChildIndex(queryGenome);
    _refChildIndex = NULL_INDEX;
  }
  else if (refGenome->getParent() == queryGenome)
  {
    _rel = RefChild;
    _queryChildIndex = NULL_INDEX;
    _refChildIndex = queryGenome->getChildIndex(refGenome);
  }
  else if (queryGenome->getParent() == refGenome->getParent())
  {
    _rel = RefSister;
    const Genome* parentGenome = queryGenome->getParent();
    _queryChildIndex = parentGenome->getChildIndex(queryGenome);
    _refChildIndex = parentGenome->getChildIndex(refGenome);
  }
  else
  {
    stringstream ss;
    ss << "Query species " << queryGenome->getName() << " is neither the "
       << "parent, child, nor sibling of the Reference species "
       << refGenome->getName();
    throw hal_exception(ss.str());
  }
}

void BlockMapper::map()
{
  SegmentIteratorConstPtr refSeg;
  hal_index_t lastIndex;
  if (_rel == RefParent)
  {
    refSeg = _refGenome->getBottomSegmentIterator();
    lastIndex = _refGenome->getNumBottomSegments();
  }
  else
  {
    refSeg = _refGenome->getTopSegmentIterator();
    lastIndex = _refGenome->getNumTopSegments();
  }

  refSeg->toSite(_absRefFirst, false);
  hal_offset_t startOffset = _absRefFirst - refSeg->getStartPosition();
  hal_offset_t endOffset = 0;
  if (_absRefLast <= refSeg->getEndPosition())
  {
    endOffset = refSeg->getEndPosition() - _absRefLast;
  }
  refSeg->slice(startOffset, endOffset);

  assert(refSeg->getStartPosition() ==  _absRefFirst);
  assert(refSeg->getEndPosition() <= _absRefLast);

  while (refSeg->getArrayIndex() < lastIndex &&
         refSeg->getStartPosition() <= _absRefLast)
  {
    if (_segMap.find(refSeg) == _segMap.end())
    {
      mapRef(refSeg);
    }
    refSeg->toRight(_absRefLast);
  }

  // Copy all the reference segments we found because
  // adding adjacencies will modify the structure
  vector<SegMap::iterator> firstRoundResults(_segMap.size());
  hal_size_t i = 0;
  for (SegMap::iterator mapIt = _segMap.begin(); mapIt != _segMap.end();
       ++mapIt)
  {
    firstRoundResults[i++] = mapIt;
  }
  // For every query for every referencec, update the map with adjacent
  // blocks when found
  for (i = 0; i < firstRoundResults.size(); ++i)
  {
    SegMap::iterator mapIt = firstRoundResults[i];
    for (SegSet::iterator setIt = mapIt->second->begin();
         setIt != mapIt->second->end(); ++setIt)
    {
      mapAdjacencies(*setIt);
    }
  }
}

void BlockMapper::addParalogies(TopSegmentIteratorConstPtr top,
                                SegSet* segSet)
{
  if (_doDupes)
  {
    while (top->hasNextParalogy() == true &&
           top->getNextParalogyIndex() != (*segSet->begin())->getArrayIndex())
    {
      top->toNextParalogy();
      segSet->insert(top->copy());
    }
  }
}

bool BlockMapper::isCanonical(TopSegmentIteratorConstPtr top)
{
  BottomSegmentIteratorConstPtr bottom =
     top->getGenome()->getParent()->getBottomSegmentIterator(
       top->getParentIndex());
  hal_index_t childIndex = top->getGenome() == _refGenome ? _refChildIndex :
     _queryChildIndex;
  return bottom->getChildIndex(childIndex) == top->getArrayIndex();
}

void BlockMapper::mapRef(SegmentIteratorConstPtr refSeg)
{
  assert(!refSeg->getReversed());
  if (_rel == RefParent)
  {
    mapRefParent(refSeg);
  }
  else if (_rel == RefChild)
  {
      mapRefChild(refSeg);
  }
  else // _rel == RefSister
  {
    mapRefSister(refSeg);
  }
}

void BlockMapper::mapRefParent(SegmentIteratorConstPtr refSeg)
{
  BottomSegmentIteratorConstPtr refBottom =
     refSeg.downCast<BottomSegmentIteratorConstPtr>();

  if (refBottom->hasChild(_queryChildIndex))
  {
    TopSegmentIteratorConstPtr queryTop = _queryGenome->getTopSegmentIterator();
    queryTop->toChild(refBottom, _queryChildIndex);
    SegSet* segSet = new SegSet();
    segSet->insert(queryTop->copy());
    addParalogies(queryTop, segSet);
    assert(_segMap.find(refBottom) == _segMap.end());
    _segMap.insert(pair<SegmentIteratorConstPtr, SegSet*>(
                     refBottom->copy(), segSet));
  }
}

void BlockMapper::mapRefChild(SegmentIteratorConstPtr refSeg)
{
  TopSegmentIteratorConstPtr refTop =
     refSeg.downCast<TopSegmentIteratorConstPtr>();

  if (refTop->hasParent() && (_doDupes || isCanonical(refTop)))
  {
    BottomSegmentIteratorConstPtr queryBottom =
       _queryGenome->getBottomSegmentIterator();
    queryBottom->toParent(refTop);
    SegSet* segSet = new SegSet();
    segSet->insert(queryBottom->copy());
    assert(_segMap.find(refTop) == _segMap.end());
    _segMap.insert(pair<SegmentIteratorConstPtr, SegSet*>(
                     refTop->copy(), segSet));
  }
}

void BlockMapper::mapRefSister(SegmentIteratorConstPtr refSeg)
{
  TopSegmentIteratorConstPtr refTop =
     refSeg.downCast<TopSegmentIteratorConstPtr>();

  if (refTop->hasParent() && (_doDupes || isCanonical(refTop)))
  {
    BottomSegmentIteratorConstPtr parBottom =
       _refGenome->getParent()->getBottomSegmentIterator();
    parBottom->toParent(refTop);
    if (parBottom->hasChild(_queryChildIndex))
    {
      TopSegmentIteratorConstPtr queryTop =
         _queryGenome->getTopSegmentIterator();
      queryTop->toChild(parBottom, _queryChildIndex);
      SegSet* segSet = new SegSet();
      segSet->insert(queryTop->copy());
      addParalogies(queryTop, segSet);
      assert(_segMap.find(queryTop) == _segMap.end());
      _segMap.insert(pair<SegmentIteratorConstPtr, SegSet*>(
                       refTop->copy(), segSet));
    }
  }
}

void BlockMapper::mapAdjacencies(SegmentIteratorConstPtr querySeg)
{
  SegmentIteratorConstPtr querySegCpy;
  SegmentIteratorConstPtr querySegCpy2;

  hal_index_t maxIndex;
  hal_index_t minIndex;
  if (_rel == RefParent || _rel == RefSister)
  {
    TopSegmentIteratorConstPtr queryTop =
       querySeg.downCast<TopSegmentIteratorConstPtr>();
    querySegCpy = queryTop->copy();
    querySegCpy2 = queryTop->copy();
    minIndex = queryTop->getSequence()->getTopSegmentArrayIndex();
    maxIndex = minIndex +
       (hal_index_t)queryTop->getSequence()->getNumTopSegments();
  }
  else
  {
    BottomSegmentIteratorConstPtr queryBottom =
       querySeg.downCast<BottomSegmentIteratorConstPtr>();
    querySegCpy = queryBottom->copy();
    querySegCpy2 = queryBottom->copy();
    minIndex = queryBottom->getSequence()->getBottomSegmentArrayIndex();
    maxIndex = minIndex +
       (hal_index_t)queryBottom->getSequence()->getNumBottomSegments();
  }

  hal_size_t iter = 0;
  querySegCpy->toRight();
  while ((querySegCpy->getReversed() ||
          querySegCpy->getArrayIndex() < maxIndex) &&
         (!querySegCpy->getReversed() ||
          querySegCpy->getArrayIndex() >= minIndex) &&
         iter < _maxAdjScan)
  {
    SegmentIteratorConstPtr refSeg = getAdjacencyInRef(querySegCpy);

    if (refSeg.get() != NULL)
    {
      // never want an inverted reference.
      if (refSeg->getReversed())
      {
        refSeg->toReverse();
        //but we don't want to keep in forward coordinates
        refSeg->slice(refSeg->getEndOffset(), refSeg->getStartOffset());
      }

      if (_segMap.find(refSeg) == _segMap.end())
      {
        mapRef(refSeg);
      }
      break;
    }
    querySegCpy->toRight();
    ++iter;
  }
  // typo prevention
  querySegCpy = SegmentIteratorConstPtr();

  iter = 0;
  querySegCpy2->toLeft();
  while ((querySegCpy2->getReversed() ||
          querySegCpy2->getArrayIndex() >= minIndex) &&
         (!querySegCpy2->getReversed() ||
          querySegCpy2->getArrayIndex() < maxIndex) &&
         iter < _maxAdjScan)
  {
    SegmentIteratorConstPtr refSeg = getAdjacencyInRef(querySegCpy2);

    if (refSeg.get() != NULL)
    {
      // never want an inverted reference.
      if (refSeg->getReversed())
      {
        refSeg->toReverse();
        //but we don't want to keep in forward coordinates
        refSeg->slice(refSeg->getEndOffset(), refSeg->getStartOffset());
      }

      if (_segMap.find(refSeg) == _segMap.end())
      {
        mapRef(refSeg);
      }
      break;
    }
    querySegCpy2->toLeft();
    ++iter;
  }
}

SegmentIteratorConstPtr BlockMapper::getAdjacencyInRef(
  SegmentIteratorConstPtr querySeg)
{
  SegmentIteratorConstPtr refSeg;
  if (_rel == RefParent)
  {
    TopSegmentIteratorConstPtr queryTop =
       querySeg.downCast<TopSegmentIteratorConstPtr>();
    if (queryTop->hasParent())
    {
      BottomSegmentIteratorConstPtr refBottom =
         _refGenome->getBottomSegmentIterator();
      refBottom->toParent(queryTop);
      refSeg = refBottom;
    }
  }
  else if (_rel == RefChild)
  {
    BottomSegmentIteratorConstPtr queryBottom =
       querySeg.downCast<BottomSegmentIteratorConstPtr>();
    if (queryBottom->hasChild(_refChildIndex))
    {
      TopSegmentIteratorConstPtr refTop =
         _refGenome->getTopSegmentIterator();
      refTop->toChild(queryBottom, _refChildIndex);
      refSeg = refTop;
    }
  }
  else // _rel == QuerySister
  {
    TopSegmentIteratorConstPtr queryTop =
       querySeg.downCast<TopSegmentIteratorConstPtr>();
    if (queryTop->hasParent())
    {
      BottomSegmentIteratorConstPtr parBot =
         queryTop->getGenome()->getParent()->getBottomSegmentIterator();
      parBot->toParent(queryTop);
      if (parBot->hasChild(_refChildIndex))
      {
        TopSegmentIteratorConstPtr refTop =
         _refGenome->getTopSegmentIterator();
        refTop->toChild(parBot, _refChildIndex);
        refSeg = refTop;
      }
    }
  }
  if (refSeg.get() != NULL)
  {
    assert(refSeg->getGenome() == _refGenome);
    if (refSeg->getSequence() != _refSequence)
    {
      refSeg = SegmentIteratorConstPtr();
    }
  }
  return refSeg;
}
<commit_msg>fix typo in assert<commit_after>/*
 * Copyright (C) 2013 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */

#include <iostream>
#include <string>
#include <set>
#include <vector>
#include <map>
#include "hal.h"
#include "halBlockMapper.h"

using namespace hal;
using namespace std;

hal_size_t BlockMapper::_maxAdjScan = 5;

BlockMapper::BlockMapper()
{

}

BlockMapper::~BlockMapper()
{
  erase();
}

void BlockMapper::erase()
{
  for (SegMap::iterator i = _segMap.begin(); i != _segMap.end(); ++i)
  {
    delete i->second;
  }
  _segMap.clear();
}

void BlockMapper::init(const Genome* refGenome, const Genome* queryGenome,
                       hal_index_t absRefFirst, hal_index_t absRefLast,
                       bool doDupes)
{
  erase();
  _absRefFirst = absRefFirst;
  _absRefLast = absRefLast;
  _doDupes = doDupes;
  _refGenome = refGenome;
  _refSequence = refGenome->getSequenceBySite(_absRefFirst);
  assert(_refSequence == refGenome->getSequenceBySite(_absRefLast));
  _queryGenome = queryGenome;

  if (queryGenome->getParent() == refGenome)
  {
    _rel = RefParent;
    _queryChildIndex = refGenome->getChildIndex(queryGenome);
    _refChildIndex = NULL_INDEX;
  }
  else if (refGenome->getParent() == queryGenome)
  {
    _rel = RefChild;
    _queryChildIndex = NULL_INDEX;
    _refChildIndex = queryGenome->getChildIndex(refGenome);
  }
  else if (queryGenome->getParent() == refGenome->getParent())
  {
    _rel = RefSister;
    const Genome* parentGenome = queryGenome->getParent();
    _queryChildIndex = parentGenome->getChildIndex(queryGenome);
    _refChildIndex = parentGenome->getChildIndex(refGenome);
  }
  else
  {
    stringstream ss;
    ss << "Query species " << queryGenome->getName() << " is neither the "
       << "parent, child, nor sibling of the Reference species "
       << refGenome->getName();
    throw hal_exception(ss.str());
  }
}

void BlockMapper::map()
{
  SegmentIteratorConstPtr refSeg;
  hal_index_t lastIndex;
  if (_rel == RefParent)
  {
    refSeg = _refGenome->getBottomSegmentIterator();
    lastIndex = _refGenome->getNumBottomSegments();
  }
  else
  {
    refSeg = _refGenome->getTopSegmentIterator();
    lastIndex = _refGenome->getNumTopSegments();
  }

  refSeg->toSite(_absRefFirst, false);
  hal_offset_t startOffset = _absRefFirst - refSeg->getStartPosition();
  hal_offset_t endOffset = 0;
  if (_absRefLast <= refSeg->getEndPosition())
  {
    endOffset = refSeg->getEndPosition() - _absRefLast;
  }
  refSeg->slice(startOffset, endOffset);

  assert(refSeg->getStartPosition() ==  _absRefFirst);
  assert(refSeg->getEndPosition() <= _absRefLast);

  while (refSeg->getArrayIndex() < lastIndex &&
         refSeg->getStartPosition() <= _absRefLast)
  {
    if (_segMap.find(refSeg) == _segMap.end())
    {
      mapRef(refSeg);
    }
    refSeg->toRight(_absRefLast);
  }

  // Copy all the reference segments we found because
  // adding adjacencies will modify the structure
  vector<SegMap::iterator> firstRoundResults(_segMap.size());
  hal_size_t i = 0;
  for (SegMap::iterator mapIt = _segMap.begin(); mapIt != _segMap.end();
       ++mapIt)
  {
    firstRoundResults[i++] = mapIt;
  }
  // For every query for every referencec, update the map with adjacent
  // blocks when found
  for (i = 0; i < firstRoundResults.size(); ++i)
  {
    SegMap::iterator mapIt = firstRoundResults[i];
    for (SegSet::iterator setIt = mapIt->second->begin();
         setIt != mapIt->second->end(); ++setIt)
    {
      mapAdjacencies(*setIt);
    }
  }
}

void BlockMapper::addParalogies(TopSegmentIteratorConstPtr top,
                                SegSet* segSet)
{
  if (_doDupes)
  {
    while (top->hasNextParalogy() == true &&
           top->getNextParalogyIndex() != (*segSet->begin())->getArrayIndex())
    {
      top->toNextParalogy();
      segSet->insert(top->copy());
    }
  }
}

bool BlockMapper::isCanonical(TopSegmentIteratorConstPtr top)
{
  BottomSegmentIteratorConstPtr bottom =
     top->getGenome()->getParent()->getBottomSegmentIterator(
       top->getParentIndex());
  hal_index_t childIndex = top->getGenome() == _refGenome ? _refChildIndex :
     _queryChildIndex;
  return bottom->getChildIndex(childIndex) == top->getArrayIndex();
}

void BlockMapper::mapRef(SegmentIteratorConstPtr refSeg)
{
  assert(!refSeg->getReversed());
  if (_rel == RefParent)
  {
    mapRefParent(refSeg);
  }
  else if (_rel == RefChild)
  {
      mapRefChild(refSeg);
  }
  else // _rel == RefSister
  {
    mapRefSister(refSeg);
  }
}

void BlockMapper::mapRefParent(SegmentIteratorConstPtr refSeg)
{
  BottomSegmentIteratorConstPtr refBottom =
     refSeg.downCast<BottomSegmentIteratorConstPtr>();

  if (refBottom->hasChild(_queryChildIndex))
  {
    TopSegmentIteratorConstPtr queryTop = _queryGenome->getTopSegmentIterator();
    queryTop->toChild(refBottom, _queryChildIndex);
    SegSet* segSet = new SegSet();
    segSet->insert(queryTop->copy());
    addParalogies(queryTop, segSet);
    assert(_segMap.find(refBottom) == _segMap.end());
    _segMap.insert(pair<SegmentIteratorConstPtr, SegSet*>(
                     refBottom->copy(), segSet));
  }
}

void BlockMapper::mapRefChild(SegmentIteratorConstPtr refSeg)
{
  TopSegmentIteratorConstPtr refTop =
     refSeg.downCast<TopSegmentIteratorConstPtr>();

  if (refTop->hasParent() && (_doDupes || isCanonical(refTop)))
  {
    BottomSegmentIteratorConstPtr queryBottom =
       _queryGenome->getBottomSegmentIterator();
    queryBottom->toParent(refTop);
    SegSet* segSet = new SegSet();
    segSet->insert(queryBottom->copy());
    assert(_segMap.find(refTop) == _segMap.end());
    _segMap.insert(pair<SegmentIteratorConstPtr, SegSet*>(
                     refTop->copy(), segSet));
  }
}

void BlockMapper::mapRefSister(SegmentIteratorConstPtr refSeg)
{
  TopSegmentIteratorConstPtr refTop =
     refSeg.downCast<TopSegmentIteratorConstPtr>();

  if (refTop->hasParent() && (_doDupes || isCanonical(refTop)))
  {
    BottomSegmentIteratorConstPtr parBottom =
       _refGenome->getParent()->getBottomSegmentIterator();
    parBottom->toParent(refTop);
    if (parBottom->hasChild(_queryChildIndex))
    {
      TopSegmentIteratorConstPtr queryTop =
         _queryGenome->getTopSegmentIterator();
      queryTop->toChild(parBottom, _queryChildIndex);
      SegSet* segSet = new SegSet();
      segSet->insert(queryTop->copy());
      addParalogies(queryTop, segSet);
      assert(_segMap.find(refTop) == _segMap.end());
      _segMap.insert(pair<SegmentIteratorConstPtr, SegSet*>(
                       refTop->copy(), segSet));
    }
  }
}

void BlockMapper::mapAdjacencies(SegmentIteratorConstPtr querySeg)
{
  SegmentIteratorConstPtr querySegCpy;
  SegmentIteratorConstPtr querySegCpy2;

  hal_index_t maxIndex;
  hal_index_t minIndex;
  if (_rel == RefParent || _rel == RefSister)
  {
    TopSegmentIteratorConstPtr queryTop =
       querySeg.downCast<TopSegmentIteratorConstPtr>();
    querySegCpy = queryTop->copy();
    querySegCpy2 = queryTop->copy();
    minIndex = queryTop->getSequence()->getTopSegmentArrayIndex();
    maxIndex = minIndex +
       (hal_index_t)queryTop->getSequence()->getNumTopSegments();
  }
  else
  {
    BottomSegmentIteratorConstPtr queryBottom =
       querySeg.downCast<BottomSegmentIteratorConstPtr>();
    querySegCpy = queryBottom->copy();
    querySegCpy2 = queryBottom->copy();
    minIndex = queryBottom->getSequence()->getBottomSegmentArrayIndex();
    maxIndex = minIndex +
       (hal_index_t)queryBottom->getSequence()->getNumBottomSegments();
  }

  hal_size_t iter = 0;
  querySegCpy->toRight();
  while ((querySegCpy->getReversed() ||
          querySegCpy->getArrayIndex() < maxIndex) &&
         (!querySegCpy->getReversed() ||
          querySegCpy->getArrayIndex() >= minIndex) &&
         iter < _maxAdjScan)
  {
    SegmentIteratorConstPtr refSeg = getAdjacencyInRef(querySegCpy);

    if (refSeg.get() != NULL)
    {
      // never want an inverted reference.
      if (refSeg->getReversed())
      {
        refSeg->toReverse();
        //but we don't want to keep in forward coordinates
        refSeg->slice(refSeg->getEndOffset(), refSeg->getStartOffset());
      }

      if (_segMap.find(refSeg) == _segMap.end())
      {
        mapRef(refSeg);
      }
      break;
    }
    querySegCpy->toRight();
    ++iter;
  }
  // typo prevention
  querySegCpy = SegmentIteratorConstPtr();

  iter = 0;
  querySegCpy2->toLeft();
  while ((querySegCpy2->getReversed() ||
          querySegCpy2->getArrayIndex() >= minIndex) &&
         (!querySegCpy2->getReversed() ||
          querySegCpy2->getArrayIndex() < maxIndex) &&
         iter < _maxAdjScan)
  {
    SegmentIteratorConstPtr refSeg = getAdjacencyInRef(querySegCpy2);

    if (refSeg.get() != NULL)
    {
      // never want an inverted reference.
      if (refSeg->getReversed())
      {
        refSeg->toReverse();
        //but we don't want to keep in forward coordinates
        refSeg->slice(refSeg->getEndOffset(), refSeg->getStartOffset());
      }

      if (_segMap.find(refSeg) == _segMap.end())
      {
        mapRef(refSeg);
      }
      break;
    }
    querySegCpy2->toLeft();
    ++iter;
  }
}

SegmentIteratorConstPtr BlockMapper::getAdjacencyInRef(
  SegmentIteratorConstPtr querySeg)
{
  SegmentIteratorConstPtr refSeg;
  if (_rel == RefParent)
  {
    TopSegmentIteratorConstPtr queryTop =
       querySeg.downCast<TopSegmentIteratorConstPtr>();
    if (queryTop->hasParent())
    {
      BottomSegmentIteratorConstPtr refBottom =
         _refGenome->getBottomSegmentIterator();
      refBottom->toParent(queryTop);
      refSeg = refBottom;
    }
  }
  else if (_rel == RefChild)
  {
    BottomSegmentIteratorConstPtr queryBottom =
       querySeg.downCast<BottomSegmentIteratorConstPtr>();
    if (queryBottom->hasChild(_refChildIndex))
    {
      TopSegmentIteratorConstPtr refTop =
         _refGenome->getTopSegmentIterator();
      refTop->toChild(queryBottom, _refChildIndex);
      refSeg = refTop;
    }
  }
  else // _rel == QuerySister
  {
    TopSegmentIteratorConstPtr queryTop =
       querySeg.downCast<TopSegmentIteratorConstPtr>();
    if (queryTop->hasParent())
    {
      BottomSegmentIteratorConstPtr parBot =
         queryTop->getGenome()->getParent()->getBottomSegmentIterator();
      parBot->toParent(queryTop);
      if (parBot->hasChild(_refChildIndex))
      {
        TopSegmentIteratorConstPtr refTop =
         _refGenome->getTopSegmentIterator();
        refTop->toChild(parBot, _refChildIndex);
        refSeg = refTop;
      }
    }
  }
  if (refSeg.get() != NULL)
  {
    assert(refSeg->getGenome() == _refGenome);
    if (refSeg->getSequence() != _refSequence)
    {
      refSeg = SegmentIteratorConstPtr();
    }
  }
  return refSeg;
}
<|endoftext|>


<commit_before>/*
 * MIT License
 * Copyright (c) 2016 Vladislav Tananaev
 */
#include "ComputationalGraph.h"
using std::string;

ComputationalGraph::ComputationalGraph()
{
    grad_input_last_gate = 1; // This is gradient input for the last gate
}

void ComputationalGraph::add(string name, Gate::Ptr g, float &input_a, float &input_b){

    // Connect inputs
    g->input_a.connect( &input_a );
    g->input_b.connect( &input_b );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    gates.insert({name, g});
    order.push_back(name);
}

void ComputationalGraph::add(string name, Gate::Ptr g, string input_a, float &input_b){

    // Find previous gate with name input_a
    // Note: throwS if element isn't found
    auto prev_g = gates.at(input_a);

    // Connect inputs
    g->input_a.connect( &(prev_g->output) );
    g->input_b.connect( &input_b );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    // Connect gradients for previous gate
    prev_g->grad_input.connect( &(g->gradout_a) );

    gates.insert({name, g});
    order.push_back(name);
}

void ComputationalGraph::add(string name, Gate::Ptr g, float &input_a, string input_b){

    // Find previous gate with name input_b
    // Note: throws if element isn't found
    auto prev_g = gates.at(input_b);

    // Connect inputs
    g->input_a.connect( &input_a );
    g->input_b.connect( &(prev_g->output) );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    // Connect gradients for previous gate
    prev_g->grad_input.connect( &(g->gradout_b) );

    gates.insert({name, g});
    order.push_back(name);
}

void ComputationalGraph::add(string name, Gate::Ptr g, string input_a, string input_b){

    // Find previous gate with name input_a
    // Note: throws if element isn't found
    auto prev_g_a = gates.at(input_a);
    // Find previous gate with name input_b
    auto prev_g_b = gates.at(input_b);

    // Connect inputs
    g->input_a.connect( &(prev_g_a->output) );
    g->input_b.connect( &(prev_g_b->output) );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    // Connect gradients for previous gates
    prev_g_a->grad_input.connect( &(g->gradout_a) );
    prev_g_b->grad_input.connect( &(g->gradout_b) );

    gates.insert({name, g});
    order.push_back(name);
}

void ComputationalGraph::add(string name, Gate::Ptr g, string input_a){

    // Find previous gate with name input_a
    // Note: throws if element isn't found
    auto prev_g_a = gates.at(input_a);

    // Connect inputs
    g->input_a.connect( &(prev_g_a->output) );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    // Connect gradients for previous gates
    prev_g_a->grad_input.connect( &(g->gradout_a) );

    gates.insert({name, g});
    order.push_back(name);
}

void ComputationalGraph::add(string name, Gate::Ptr g, float &input_a){

    // Connect inputs
    g->input_a.connect( &input_a );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    gates.insert({name, g});
    order.push_back(name);
}

void ComputationalGraph::forward(){
    // Call gates in topological order
    for (auto it = order.begin(); it!=order.end(); ++it){
        auto g = gates.at(*it);
        g->forward();
        std::cout << "[forward] Gate " << *it << " output is " << g->output << std::endl;
    }
}

void ComputationalGraph::backward(){
    // Call gates in reverse topological order
    for (auto it = order.rbegin(); it!=order.rend(); ++it){
        auto g = gates.at(*it);
        g->backward();

        std::cout << "[backward] Gate " << *it << " gradoutput_a is " << g->gradout_a;
        if(!g->unary){
            std::cout << " gradoutput_b is " << g->gradout_b;
        }
        std::cout << std::endl;

    }
}

ComputationalGraph::~ComputationalGraph(){}
<commit_msg>Change pushes to emplace.<commit_after>/*
 * MIT License
 * Copyright (c) 2016 Vladislav Tananaev
 */
#include "ComputationalGraph.h"
using std::string;

ComputationalGraph::ComputationalGraph()
{
    grad_input_last_gate = 1; // This is gradient input for the last gate
}

void ComputationalGraph::add(string name, Gate::Ptr g, float &input_a, float &input_b){

    // Connect inputs
    g->input_a.connect( &input_a );
    g->input_b.connect( &input_b );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    gates.emplace(name, g);
    order.emplace_back(name);
}

void ComputationalGraph::add(string name, Gate::Ptr g, string input_a, float &input_b){

    // Find previous gate with name input_a
    // Note: throwS if element isn't found
    auto prev_g = gates.at(input_a);

    // Connect inputs
    g->input_a.connect( &(prev_g->output) );
    g->input_b.connect( &input_b );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    // Connect gradients for previous gate
    prev_g->grad_input.connect( &(g->gradout_a) );

    gates.emplace(name, g);
    order.emplace_back(name);
}

void ComputationalGraph::add(string name, Gate::Ptr g, float &input_a, string input_b){

    // Find previous gate with name input_b
    // Note: throws if element isn't found
    auto prev_g = gates.at(input_b);

    // Connect inputs
    g->input_a.connect( &input_a );
    g->input_b.connect( &(prev_g->output) );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    // Connect gradients for previous gate
    prev_g->grad_input.connect( &(g->gradout_b) );

    gates.emplace(name, g);
    order.emplace_back(name);
}

void ComputationalGraph::add(string name, Gate::Ptr g, string input_a, string input_b){

    // Find previous gate with name input_a
    // Note: throws if element isn't found
    auto prev_g_a = gates.at(input_a);
    // Find previous gate with name input_b
    auto prev_g_b = gates.at(input_b);

    // Connect inputs
    g->input_a.connect( &(prev_g_a->output) );
    g->input_b.connect( &(prev_g_b->output) );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    // Connect gradients for previous gates
    prev_g_a->grad_input.connect( &(g->gradout_a) );
    prev_g_b->grad_input.connect( &(g->gradout_b) );

    gates.emplace(name, g);
    order.emplace_back(name);
}

void ComputationalGraph::add(string name, Gate::Ptr g, string input_a){

    // Find previous gate with name input_a
    // Note: throws if element isn't found
    auto prev_g_a = gates.at(input_a);

    // Connect inputs
    g->input_a.connect( &(prev_g_a->output) );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    // Connect gradients for previous gates
    prev_g_a->grad_input.connect( &(g->gradout_a) );

    gates.emplace(name, g);
    order.emplace_back(name);
}

void ComputationalGraph::add(string name, Gate::Ptr g, float &input_a){

    // Connect inputs
    g->input_a.connect( &input_a );

    // Default gradient input for this gate
    g->grad_input.connect( &grad_input_last_gate );

    gates.emplace(name, g);
    order.emplace_back(name);
}

void ComputationalGraph::forward(){
    // Call gates in topological order
    for (auto it = order.begin(); it!=order.end(); ++it){
        auto g = gates.at(*it);
        g->forward();
        std::cout << "[forward] Gate " << *it << " output is " << g->output << std::endl;
    }
}

void ComputationalGraph::backward(){
    // Call gates in reverse topological order
    for (auto it = order.rbegin(); it!=order.rend(); ++it){
        auto g = gates.at(*it);
        g->backward();

        std::cout << "[backward] Gate " << *it << " gradoutput_a is " << g->gradout_a;
        if(!g->unary){
            std::cout << " gradoutput_b is " << g->gradout_b;
        }
        std::cout << std::endl;

    }
}

ComputationalGraph::~ComputationalGraph(){}
<|endoftext|>


<commit_before>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
// vim:sts=8:sw=8:ts=8:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/* Copyright (c) FFLAS-FFPACK
* Written by Bastien Vialla <bastien.vialla@lirmm.fr>
* ========LICENCE========
* This file is part of the library FFLAS-FFPACK.
*
* FFLAS-FFPACK is free software: you can redistribute it and/or modify
* it under the terms of the  GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
* ========LICENCE========
*/

#include <iostream>
#include <vector>
#include <sstream>
#include <cstdio>
#include <cstdlib>

#include "givaro/modular.h"
#include "givaro/modular-balanced.h"

#include "fflas-ffpack/config-blas.h"
// #include "fflas-ffpac/field/modular-double.h"
#include "fflas-ffpack/fflas/fflas.h"
#include "fflas-ffpack/fflas/fflas_sparse.h"
#include "fflas-ffpack/utils/timer.h"
#include "fflas-ffpack/utils/args-parser.h"

#ifdef __FFLASFFPACK_USE_OPENMP
typedef FFLAS::OMPTimer TTimer;
#else
typedef FFLAS::Timer TTimer;
#endif

using namespace std;
using namespace FFLAS;

template <typename T> T from_string(std::string const &s) {
    std::stringstream ss(s);
    T result;
    ss >> result; // TODO handle errors
    return result;
}

template <class MatT, class Field, class IndexT>
std::pair<double, uint64_t> test_fspmv(size_t iter, const Field &F, IndexT *row, IndexT *col,
                                       typename Field::Element_ptr dat, index_t rowdim, index_t coldim, uint64_t nnz,
                                       typename Field::Element_ptr x, typename Field::Element_ptr y,
                                       typename Field::Element beta) {
    MatT matrix;
    sparse_init(F, matrix, row, col, dat, rowdim, coldim, nnz);
    TTimer time;
    time.clear();
    time.start();
    for (size_t i = 0; i < iter; ++i)
        fspmv(F, matrix, x, 1, y);
    time.stop();
    sparse_delete(matrix);
    return make_pair(time.usertime(), matrix.nElements);
}

template <class T1, class T2, class T> void print_res(pair<T1, T2> &p, size_t iter, T as, int blocksize = 1) {
    std::cout << "Time: " << p.first / double(iter)
              << " Gflops: " << (2 * blocksize * p.second) / 1000000000. / p.first * double(iter);
    FFLAS::writeCommandString(std::cout, as) << std::endl;
}

int main(int argc, char **argv) {

    using Field = Givaro::Modular<int64_t,int64_t>;
    using Element = typename Field::Element;

    size_t iter = 10;
    Givaro::Integer q = 1009;
    int s = 0;
    std::string matrixFile = "";

    Argument as[] = { { 'q', "-q Q", "Set the field characteristic (-1 for random).", TYPE_INTEGER, &q },
                      { 'i', "-i R", "Set number of repetitions.", TYPE_INT, &iter },
                      { 's', "-s S", "Compute and print matrix statistics.", TYPE_INT, &s },
                      { 'f', "-f FILE", "Set matrix file.", TYPE_STR, &matrixFile },
                      END_OF_ARGUMENTS };

    // matrixFile = "matrix/cis.mk8-8.sms";
    // matrixFile = "matrix/GL7d17.sms";
    // matrixFile = "data/mat11.sms";

    FFLAS::parseArguments(argc, argv, as);

    // cout << matrixFile << endl;

    Field F(q);

    index_t *row = nullptr, *col = nullptr;
    typename Field::Element_ptr dat;
    index_t rowdim = 0, coldim = 0;
    uint64_t nnz;

    if ( (matrixFile.find(".sms") != std::string::npos) || (matrixFile.find(".smf") != std::string::npos)) {
	    index_t * st = nullptr ;
        readSmsFormat(matrixFile, F, st, col, dat, rowdim, coldim, nnz);
	row = fflas_new<index_t>(nnz);
	for (index_t j = 0 ; j < rowdim ; ++j) {
		for (index_t k = st[j] ; k < st[j+1] ; ++k)
			row[k] = j ;
	}
    } else if (matrixFile.find(".spr") != std::string::npos) {
        readSprFormat(matrixFile, F, row, col, dat, rowdim, coldim, nnz);
    }

    if (s) {
        //auto stats = sparse_details::getStat(F, row, col, dat, rowdim, coldim, nnz);
        //std::cout << "Sparse Matrix statistics : " << std::endl;
        //stats.print();
        //std::cout << std::endl;
    }

    auto x = FFLAS::fflas_new(F, coldim, 1, Alignment::CACHE_LINE);
    auto y = FFLAS::fflas_new(F, rowdim, 1, Alignment::CACHE_LINE);

    for (size_t i = 0; i < coldim; ++i) {
        x[i] = 1;
    }

    for (size_t i = 0; i < rowdim; ++i) {
        y[i] = 0;
    }

    auto coo =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::COO>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "COO : ";
    print_res(coo, iter, as);
    auto coozo =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::COO_ZO>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "COO_ZO : ";
    print_res(coozo, iter, as);
    auto csr =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::CSR>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "CSR : ";
    print_res(csr, iter, as);
    auto csrzo =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::CSR_ZO>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "CSR_ZO : ";
    print_res(csrzo, iter, as);
    auto ell =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::ELL>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "ELL : ";
    print_res(ell, iter, as);
    auto ellzo =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::ELL_ZO>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "ELL_ZO : ";
    print_res(ellzo, iter, as);
    // auto ellsimd = test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::ELL_simd>>(iter, F, row, col, dat, rowdim, coldim,
                                                                              // nnz, x, y, 1);
    // cout << "ELL_simd : ";
    // print_res(ellsimd, iter, as);
    // auto ellsimdzo = test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::ELL_simd_ZO>>(iter, F, row, col, dat, rowdim,
    //                                                                                coldim, nnz, x, y, 1);
    // cout << "ELL_simd_ZO : ";
    // print_res(ellsimdzo, iter, as);
    auto csrhyb =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::CSR_HYB>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "CSR_HYB : ";
    print_res(csrhyb, iter, as);
    auto hybzo =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::HYB_ZO>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "HYB_ZO : ";
    print_res(hybzo, iter, as);
    // -----------
    // Standard output for benchmark - Alexis Breust 2014/11/14

    // std::cout << "Time: " << coo.first / double(iter)
    // 		  << " Gflops: " << (2*coo.second)/1000000000. / coo.first * double(iter);
    // FFLAS::writeCommandString(std::cout, as) << std::endl;

    //  std::cout << "Time: " << csr.first / double(iter)
    //        << " Gflops: " << (2*csr.second)/1000000000. / csr.first * double(iter);
    //  FFLAS::writeCommandString(std::cout, as) << std::endl;
    return 0;
}
<commit_msg>unsued comment<commit_after>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
// vim:sts=8:sw=8:ts=8:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/* Copyright (c) FFLAS-FFPACK
* Written by Bastien Vialla <bastien.vialla@lirmm.fr>
* ========LICENCE========
* This file is part of the library FFLAS-FFPACK.
*
* FFLAS-FFPACK is free software: you can redistribute it and/or modify
* it under the terms of the  GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
* ========LICENCE========
*/

#include <iostream>
#include <vector>
#include <sstream>
#include <cstdio>
#include <cstdlib>

#include "givaro/modular.h"
#include "givaro/modular-balanced.h"

#include "fflas-ffpack/config-blas.h"
#include "fflas-ffpack/fflas/fflas.h"
#include "fflas-ffpack/fflas/fflas_sparse.h"
#include "fflas-ffpack/utils/timer.h"
#include "fflas-ffpack/utils/args-parser.h"

#ifdef __FFLASFFPACK_USE_OPENMP
typedef FFLAS::OMPTimer TTimer;
#else
typedef FFLAS::Timer TTimer;
#endif

using namespace std;
using namespace FFLAS;

template <typename T> T from_string(std::string const &s) {
    std::stringstream ss(s);
    T result;
    ss >> result; // TODO handle errors
    return result;
}

template <class MatT, class Field, class IndexT>
std::pair<double, uint64_t> test_fspmv(size_t iter, const Field &F, IndexT *row, IndexT *col,
                                       typename Field::Element_ptr dat, index_t rowdim, index_t coldim, uint64_t nnz,
                                       typename Field::Element_ptr x, typename Field::Element_ptr y,
                                       typename Field::Element beta) {
    MatT matrix;
    sparse_init(F, matrix, row, col, dat, rowdim, coldim, nnz);
    TTimer time;
    time.clear();
    time.start();
    for (size_t i = 0; i < iter; ++i)
        fspmv(F, matrix, x, 1, y);
    time.stop();
    sparse_delete(matrix);
    return make_pair(time.usertime(), matrix.nElements);
}

template <class T1, class T2, class T> void print_res(pair<T1, T2> &p, size_t iter, T as, int blocksize = 1) {
    std::cout << "Time: " << p.first / double(iter)
              << " Gflops: " << (2 * blocksize * p.second) / 1000000000. / p.first * double(iter);
    FFLAS::writeCommandString(std::cout, as) << std::endl;
}

int main(int argc, char **argv) {

    using Field = Givaro::Modular<int64_t,int64_t>;
    using Element = typename Field::Element;

    size_t iter = 10;
    Givaro::Integer q = 1009;
    int s = 0;
    std::string matrixFile = "";

    Argument as[] = { { 'q', "-q Q", "Set the field characteristic (-1 for random).", TYPE_INTEGER, &q },
                      { 'i', "-i R", "Set number of repetitions.", TYPE_INT, &iter },
                      { 's', "-s S", "Compute and print matrix statistics.", TYPE_INT, &s },
                      { 'f', "-f FILE", "Set matrix file.", TYPE_STR, &matrixFile },
                      END_OF_ARGUMENTS };

    // matrixFile = "matrix/cis.mk8-8.sms";
    // matrixFile = "matrix/GL7d17.sms";
    // matrixFile = "data/mat11.sms";

    FFLAS::parseArguments(argc, argv, as);

    // cout << matrixFile << endl;

    Field F(q);

    index_t *row = nullptr, *col = nullptr;
    typename Field::Element_ptr dat;
    index_t rowdim = 0, coldim = 0;
    uint64_t nnz;

    if ( (matrixFile.find(".sms") != std::string::npos) || (matrixFile.find(".smf") != std::string::npos)) {
	    index_t * st = nullptr ;
        readSmsFormat(matrixFile, F, st, col, dat, rowdim, coldim, nnz);
	row = fflas_new<index_t>(nnz);
	for (index_t j = 0 ; j < rowdim ; ++j) {
		for (index_t k = st[j] ; k < st[j+1] ; ++k)
			row[k] = j ;
	}
    } else if (matrixFile.find(".spr") != std::string::npos) {
        readSprFormat(matrixFile, F, row, col, dat, rowdim, coldim, nnz);
    }

    if (s) {
        //auto stats = sparse_details::getStat(F, row, col, dat, rowdim, coldim, nnz);
        //std::cout << "Sparse Matrix statistics : " << std::endl;
        //stats.print();
        //std::cout << std::endl;
    }

    auto x = FFLAS::fflas_new(F, coldim, 1, Alignment::CACHE_LINE);
    auto y = FFLAS::fflas_new(F, rowdim, 1, Alignment::CACHE_LINE);

    for (size_t i = 0; i < coldim; ++i) {
        x[i] = 1;
    }

    for (size_t i = 0; i < rowdim; ++i) {
        y[i] = 0;
    }

    auto coo =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::COO>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "COO : ";
    print_res(coo, iter, as);
    auto coozo =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::COO_ZO>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "COO_ZO : ";
    print_res(coozo, iter, as);
    auto csr =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::CSR>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "CSR : ";
    print_res(csr, iter, as);
    auto csrzo =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::CSR_ZO>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "CSR_ZO : ";
    print_res(csrzo, iter, as);
    auto ell =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::ELL>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "ELL : ";
    print_res(ell, iter, as);
    auto ellzo =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::ELL_ZO>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "ELL_ZO : ";
    print_res(ellzo, iter, as);
    // auto ellsimd = test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::ELL_simd>>(iter, F, row, col, dat, rowdim, coldim,
                                                                              // nnz, x, y, 1);
    // cout << "ELL_simd : ";
    // print_res(ellsimd, iter, as);
    // auto ellsimdzo = test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::ELL_simd_ZO>>(iter, F, row, col, dat, rowdim,
    //                                                                                coldim, nnz, x, y, 1);
    // cout << "ELL_simd_ZO : ";
    // print_res(ellsimdzo, iter, as);
    auto csrhyb =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::CSR_HYB>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "CSR_HYB : ";
    print_res(csrhyb, iter, as);
    auto hybzo =
        test_fspmv<Sparse<Field, FFLAS::SparseMatrix_t::HYB_ZO>>(iter, F, row, col, dat, rowdim, coldim, nnz, x, y, 1);
    cout << "HYB_ZO : ";
    print_res(hybzo, iter, as);
    // -----------
    // Standard output for benchmark - Alexis Breust 2014/11/14

    // std::cout << "Time: " << coo.first / double(iter)
    // 		  << " Gflops: " << (2*coo.second)/1000000000. / coo.first * double(iter);
    // FFLAS::writeCommandString(std::cout, as) << std::endl;

    //  std::cout << "Time: " << csr.first / double(iter)
    //        << " Gflops: " << (2*csr.second)/1000000000. / csr.first * double(iter);
    //  FFLAS::writeCommandString(std::cout, as) << std::endl;
    return 0;
}
<|endoftext|>


<commit_before>#include "Log.h"
#include <iostream>

namespace spdlog
{
	namespace sinks
	{

		template <class Mutex>
		class stdout_sink_no_debug : public base_sink<Mutex>
		{
			using MyType = stdout_sink_no_debug<Mutex>;
		public:
			stdout_sink_no_debug() {}
			static std::shared_ptr<MyType> instance()
			{
				static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
				return instance;
			}

			void _sink_it(const details::log_msg& msg) override
			{
				if (msg.level >= level::info) {
					fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout);
					flush();
				}
			}

			void flush() override
			{
				fflush(stdout);
			}
		};

		typedef stdout_sink_no_debug<details::null_mutex> stdout_sink_no_debug_st;
		typedef stdout_sink_no_debug<std::mutex> stdout_sink_no_debug_mt; // ̰߳ȫ
	}
}

CLog::CLog() {

    try {
        std::vector<spdlog::sink_ptr> sinks;
        sinks.push_back(std::make_shared<spdlog::sinks::stdout_sink_mt>());
        sinks.push_back(std::make_shared<spdlog::sinks::daily_file_sink_mt>("logfile", "txt", 0, 0));
        auto combined_logger = std::make_shared<spdlog::logger>("log", begin(sinks), end(sinks));
        combined_logger->flush_on(spdlog::level::err); // trigger flush if the log severity is error or higher
        spdlog::register_logger(combined_logger);

        //[%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
        spd::set_pattern("[%H:%M:%S %e] [%L] [%t] %v");
		spd::set_level(spd::level::debug);
    } catch (const spdlog::spdlog_ex& ex) {
        std::cout << "Log failed: " << ex.what() << std::endl;
    }

}

CLog::~CLog() {
    // Under VisualStudio, this must be called before main finishes to workaround a known VS issue
    spdlog::drop_all();
}

CLog nono;
<commit_msg>ubuntu<commit_after>#include "Log.h"
#include <iostream>

namespace spdlog
{
	namespace sinks
	{

		template <class Mutex>
		class stdout_sink_no_debug : public base_sink<Mutex>
		{
			using MyType = stdout_sink_no_debug<Mutex>;
		public:
			stdout_sink_no_debug() {}
			static std::shared_ptr<MyType> instance()
			{
				static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
				return instance;
			}

			void _sink_it(const details::log_msg& msg) override
			{
				if (msg.level >= level::info) {
					fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout);
					flush();
				}
			}

			void flush() override
			{
				fflush(stdout);
			}
		};

		typedef stdout_sink_no_debug<details::null_mutex> stdout_sink_no_debug_st;
		typedef stdout_sink_no_debug<std::mutex> stdout_sink_no_debug_mt; // ̰߳ȫ
	}
}

CLog::CLog() {

    try {
        std::vector<spdlog::sink_ptr> sinks;
        sinks.push_back(std::make_shared<spdlog::sinks::stdout_sink_mt>());
        sinks.push_back(std::make_shared<spdlog::sinks::daily_file_sink_mt>("logfile", "txt", 0, 0));
        auto combined_logger = std::make_shared<spdlog::logger>("log", begin(sinks), end(sinks));
        //combined_logger->flush_on(spdlog::level::err); // trigger flush if the log severity is error or higher
        spdlog::register_logger(combined_logger);

        //[%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
        spd::set_pattern("[%H:%M:%S %e] [%L] [%t] %v");
		spd::set_level(spd::level::debug);
    } catch (const spdlog::spdlog_ex& ex) {
        std::cout << "Log failed: " << ex.what() << std::endl;
    }

}

CLog::~CLog() {
    // Under VisualStudio, this must be called before main finishes to workaround a known VS issue
    spdlog::drop_all();
}

CLog nono;
<|endoftext|>


<commit_before>/*
 *******************************************************************************
 *
 * Purpose: Low Power Mode implementation
 *
 *******************************************************************************
 * Copyright Monstrenyatko 2014.
 *
 * Distributed under the MIT License.
 * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT)
 *******************************************************************************
 */

/* Internal Includes */
#include "LPM.h"
#include "Logger.h"
#include "butler-arduino-sensor.h"
/* External Includes */
/* System Includes */
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include <avr/interrupt.h>

#define LPM_CLOCK_PRESCALER_1024	(_BV (CS20) | _BV(CS21) | _BV (CS22))
#define LPM_CLOCK_PRESCALER_128		(_BV (CS20) | _BV (CS22))
#define LPM_CLOCK_PRESCALER_64		(_BV (CS22))

#if F_CPU == 8000000
	#define LPM_CLOCK_SMALL_PRESCALER					64
	#define LPM_CLOCK_SMALL_PRESCALER_TCCR2B			LPM_CLOCK_PRESCALER_64
	// 0.001/(1/(F_CPU)*SMALL_PRESCALER)
	#define LPM_CLOCK_SMALL_TICKS_MAX					(125-1) // zero is relative
	#define LPM_CLOCK_SMALL_INTERRUPT_MS_QTY			1
	#define LPM_CLOCK_BIG_PRESCALER						1024
	#define LPM_CLOCK_BIG_PRESCALER_TCCR2B				LPM_CLOCK_PRESCALER_1024
	// 0.032/(1/(F_CPU)*BIG_PRESCALER)
	#define LPM_CLOCK_BIG_TICKS_MAX						(250-1) // zero is relative
	#define LPM_CLOCK_BIG_INTERRUPT_MS_QTY				32
#elif F_CPU == 16000000
	#define LPM_CLOCK_SMALL_PRESCALER					128
	#define LPM_CLOCK_SMALL_PRESCALER_TCCR2B			LPM_CLOCK_PRESCALER_128
	// 0.001/(1/(F_CPU)*SMALL_PRESCALER)
	#define LPM_CLOCK_SMALL_TICKS_MAX					(125-1) // zero is relative
	#define LPM_CLOCK_SMALL_INTERRUPT_MS_QTY			1
	#define LPM_CLOCK_BIG_PRESCALER						1024
	#define LPM_CLOCK_BIG_PRESCALER_TCCR2B				LPM_CLOCK_PRESCALER_1024
	#define LPM_CLOCK_BIG_INTERRUPT_MS_QTY				16
	// 0.016/(1/(F_CPU)*BIG_PRESCALER)
	#define LPM_CLOCK_BIG_TICKS_MAX						(250-1) // zero is relative
#else
	#error Unsupported CPU Frequency
#endif

#define LPM_CLOCK_BIG_TICKS_PER_1_MS	(0.001/(1./(F_CPU)*LPM_CLOCK_BIG_PRESCALER))
#define LPM_CLOCK_SMALL_TICKS_PER_1_MS	(0.001/(1./(F_CPU)*LPM_CLOCK_SMALL_PRESCALER))

volatile unsigned long lpmClockInterruptsQty = 0;
uint8_t clock_0_TIMSK = 0;
LpmConfig Lpm::mConfig;

ISR (TIMER2_COMPA_vect)
{
	++lpmClockInterruptsQty;
}

void Lpm::init(const LpmConfig& config) {
	mConfig = config;
	digitalWrite(mConfig.pinLedAwake, HIGH);
	resetClock();
	clock_0_TIMSK = TIMSK0;
}

void stopSysClock() {
	// save state
	clock_0_TIMSK = TIMSK0;
	// disable interrupts
	TIMSK0 = 0;
	// clean flags
	TIFR0 = 0;
}

void restoreSysClock() {
	// restore
	TIMSK0 = clock_0_TIMSK;
}

void Lpm::idle(uint32_t ms) {
	unsigned long start = millis();
	while (ms > 0) {
		if (ms>1) {
			bool clockSmall = (ms<LPM_CLOCK_BIG_INTERRUPT_MS_QTY);
			stopSysClock();
			if (clockSmall) {
				startClockSmall();
			} else {
				startClockBig();
			}
			// go to low power
			{
				digitalWrite(mConfig.pinLedAwake, LOW);
				switch(mConfig.mode) {
					case LPM_MODE_PWR_SAVE:
						set_sleep_mode(SLEEP_MODE_PWR_SAVE);
						break;
					case LPM_MODE_IDLE:
					default:
						set_sleep_mode(SLEEP_MODE_IDLE);
					break;
				}
				cli();
				sleep_enable();
				power_adc_disable();
				power_spi_disable();
				power_timer0_disable();
				power_timer1_disable();
				//power_timer2_disable() => need to keep time tracking
				power_twi_disable();
				sei();
				sleep_cpu();
				sleep_disable();
				sei();
				power_all_enable();
				// awake from here
				digitalWrite(mConfig.pinLedAwake, HIGH);
			}
			stopClock();
			if(clockSmall) {
				updateSysClockSmall();
			} else {
				updateSysClockBig();
			}
			restoreSysClock();
		}
		// calculate time
		{
			unsigned long current = millis();
			unsigned long delta = current - start;
			if (delta < ms) {
				ms -= delta;
				start = current;
			} else {
				ms = 0;
			}
		}
	}
}

void Lpm::startClockBig() {
	stopClock();
	// set
	lpmClockInterruptsQty = 0;
	TCNT2 = 0;
	OCR2A = LPM_CLOCK_BIG_TICKS_MAX;				// set TOP
	OCR2B = 0;
	GTCCR = _BV (PSRASY);							// reset prescaler
	TCCR2A = _BV(WGM21);							// CTC mode
	TCCR2B = LPM_CLOCK_BIG_PRESCALER_TCCR2B;		// set prescaler
	// start
	TIMSK2 = _BV(OCIE2A);
}

void Lpm::updateSysClockBig() {
	// 1 of .. == BIG_INTERRUPT_MS_QTY ms
	unsigned long tmp = lpmClockInterruptsQty*LPM_CLOCK_BIG_INTERRUPT_MS_QTY;
	// get ticks qty per 1ms
	double remainder = TCNT2/LPM_CLOCK_BIG_TICKS_PER_1_MS;
	tmp += round(remainder); //add the remainder with rounding
	extern volatile unsigned long timer0_millis;
	timer0_millis += tmp;
}

void Lpm::startClockSmall() {
	stopClock();
	// set
	lpmClockInterruptsQty = 0;
	TCNT2 = 0;
	OCR2A = LPM_CLOCK_SMALL_TICKS_MAX;				// set TOP
	OCR2B = 0;
	GTCCR = _BV (PSRASY);							// reset prescaler
	TCCR2A = _BV(WGM21);							// CTC mode
	TCCR2B = LPM_CLOCK_SMALL_PRESCALER_TCCR2B;		// set prescaler
	// start
	TIMSK2 = _BV(OCIE2A);
}

void Lpm::updateSysClockSmall() {
	// 1 of .. == SMALL_INTERRUPT_MS_QTY ms
	unsigned long tmp = lpmClockInterruptsQty*LPM_CLOCK_SMALL_INTERRUPT_MS_QTY;
	// get ticks qty per 1ms
	double remainder = TCNT2/LPM_CLOCK_SMALL_TICKS_PER_1_MS;
	tmp += round(remainder); //add the remainder with rounding
	extern volatile unsigned long timer0_millis;
	timer0_millis += tmp;
}

void Lpm::stopClock() {
	TCCR2B=0; // No clock source (Timer/Counter stopped).
	TIMSK2=0; // disable interrupts
}

void Lpm::resetClock() {
	// disable interrupts
	TIMSK2 = 0;
	// set clock source to asynchronous
	ASSR = _BV(AS2);
	// set all registers
	TCNT2 = 0;
	OCR2A = 0;
	OCR2B = 0;
	TCCR2A = 0;
	TCCR2B = 0;
	// wait a bit
	delay(1);
	// clean flags
	TIFR2 = 0;
}
<commit_msg>Fix LPM awake led was always ON.<commit_after>/*
 *******************************************************************************
 *
 * Purpose: Low Power Mode implementation
 *
 *******************************************************************************
 * Copyright Monstrenyatko 2014.
 *
 * Distributed under the MIT License.
 * (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT)
 *******************************************************************************
 */

/* Internal Includes */
#include "LPM.h"
#include "Logger.h"
#include "butler-arduino-sensor.h"
/* External Includes */
/* System Includes */
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include <avr/interrupt.h>

#define LPM_CLOCK_PRESCALER_1024	(_BV (CS20) | _BV(CS21) | _BV (CS22))
#define LPM_CLOCK_PRESCALER_128		(_BV (CS20) | _BV (CS22))
#define LPM_CLOCK_PRESCALER_64		(_BV (CS22))

#if F_CPU == 8000000
	#define LPM_CLOCK_SMALL_PRESCALER					64
	#define LPM_CLOCK_SMALL_PRESCALER_TCCR2B			LPM_CLOCK_PRESCALER_64
	// 0.001/(1/(F_CPU)*SMALL_PRESCALER)
	#define LPM_CLOCK_SMALL_TICKS_MAX					(125-1) // zero is relative
	#define LPM_CLOCK_SMALL_INTERRUPT_MS_QTY			1
	#define LPM_CLOCK_BIG_PRESCALER						1024
	#define LPM_CLOCK_BIG_PRESCALER_TCCR2B				LPM_CLOCK_PRESCALER_1024
	// 0.032/(1/(F_CPU)*BIG_PRESCALER)
	#define LPM_CLOCK_BIG_TICKS_MAX						(250-1) // zero is relative
	#define LPM_CLOCK_BIG_INTERRUPT_MS_QTY				32
#elif F_CPU == 16000000
	#define LPM_CLOCK_SMALL_PRESCALER					128
	#define LPM_CLOCK_SMALL_PRESCALER_TCCR2B			LPM_CLOCK_PRESCALER_128
	// 0.001/(1/(F_CPU)*SMALL_PRESCALER)
	#define LPM_CLOCK_SMALL_TICKS_MAX					(125-1) // zero is relative
	#define LPM_CLOCK_SMALL_INTERRUPT_MS_QTY			1
	#define LPM_CLOCK_BIG_PRESCALER						1024
	#define LPM_CLOCK_BIG_PRESCALER_TCCR2B				LPM_CLOCK_PRESCALER_1024
	#define LPM_CLOCK_BIG_INTERRUPT_MS_QTY				16
	// 0.016/(1/(F_CPU)*BIG_PRESCALER)
	#define LPM_CLOCK_BIG_TICKS_MAX						(250-1) // zero is relative
#else
	#error Unsupported CPU Frequency
#endif

#define LPM_CLOCK_BIG_TICKS_PER_1_MS	(0.001/(1./(F_CPU)*LPM_CLOCK_BIG_PRESCALER))
#define LPM_CLOCK_SMALL_TICKS_PER_1_MS	(0.001/(1./(F_CPU)*LPM_CLOCK_SMALL_PRESCALER))

volatile unsigned long lpmClockInterruptsQty = 0;
uint8_t clock_0_TIMSK = 0;
LpmConfig Lpm::mConfig;

ISR (TIMER2_COMPA_vect)
{
	++lpmClockInterruptsQty;
}

void Lpm::init(const LpmConfig& config) {
	mConfig = config;
	pinMode(mConfig.pinLedAwake, OUTPUT);
	digitalWrite(mConfig.pinLedAwake, HIGH);
	resetClock();
	clock_0_TIMSK = TIMSK0;
}

void stopSysClock() {
	// save state
	clock_0_TIMSK = TIMSK0;
	// disable interrupts
	TIMSK0 = 0;
	// clean flags
	TIFR0 = 0;
}

void restoreSysClock() {
	// restore
	TIMSK0 = clock_0_TIMSK;
}

void Lpm::idle(uint32_t ms) {
	unsigned long start = millis();
	while (ms > 0) {
		if (ms>1) {
			bool clockSmall = (ms<LPM_CLOCK_BIG_INTERRUPT_MS_QTY);
			stopSysClock();
			if (clockSmall) {
				startClockSmall();
			} else {
				startClockBig();
			}
			// go to low power
			{
				digitalWrite(mConfig.pinLedAwake, LOW);
				switch(mConfig.mode) {
					case LPM_MODE_PWR_SAVE:
						set_sleep_mode(SLEEP_MODE_PWR_SAVE);
						break;
					case LPM_MODE_IDLE:
					default:
						set_sleep_mode(SLEEP_MODE_IDLE);
					break;
				}
				cli();
				sleep_enable();
				power_adc_disable();
				power_spi_disable();
				power_timer0_disable();
				power_timer1_disable();
				//power_timer2_disable() => need to keep time tracking
				power_twi_disable();
				sei();
				sleep_cpu();
				sleep_disable();
				sei();
				power_all_enable();
				// awake from here
				digitalWrite(mConfig.pinLedAwake, HIGH);
			}
			stopClock();
			if(clockSmall) {
				updateSysClockSmall();
			} else {
				updateSysClockBig();
			}
			restoreSysClock();
		}
		// calculate time
		{
			unsigned long current = millis();
			unsigned long delta = current - start;
			if (delta < ms) {
				ms -= delta;
				start = current;
			} else {
				ms = 0;
			}
		}
	}
}

void Lpm::startClockBig() {
	stopClock();
	// set
	lpmClockInterruptsQty = 0;
	TCNT2 = 0;
	OCR2A = LPM_CLOCK_BIG_TICKS_MAX;				// set TOP
	OCR2B = 0;
	GTCCR = _BV (PSRASY);							// reset prescaler
	TCCR2A = _BV(WGM21);							// CTC mode
	TCCR2B = LPM_CLOCK_BIG_PRESCALER_TCCR2B;		// set prescaler
	// start
	TIMSK2 = _BV(OCIE2A);
}

void Lpm::updateSysClockBig() {
	// 1 of .. == BIG_INTERRUPT_MS_QTY ms
	unsigned long tmp = lpmClockInterruptsQty*LPM_CLOCK_BIG_INTERRUPT_MS_QTY;
	// get ticks qty per 1ms
	double remainder = TCNT2/LPM_CLOCK_BIG_TICKS_PER_1_MS;
	tmp += round(remainder); //add the remainder with rounding
	extern volatile unsigned long timer0_millis;
	timer0_millis += tmp;
}

void Lpm::startClockSmall() {
	stopClock();
	// set
	lpmClockInterruptsQty = 0;
	TCNT2 = 0;
	OCR2A = LPM_CLOCK_SMALL_TICKS_MAX;				// set TOP
	OCR2B = 0;
	GTCCR = _BV (PSRASY);							// reset prescaler
	TCCR2A = _BV(WGM21);							// CTC mode
	TCCR2B = LPM_CLOCK_SMALL_PRESCALER_TCCR2B;		// set prescaler
	// start
	TIMSK2 = _BV(OCIE2A);
}

void Lpm::updateSysClockSmall() {
	// 1 of .. == SMALL_INTERRUPT_MS_QTY ms
	unsigned long tmp = lpmClockInterruptsQty*LPM_CLOCK_SMALL_INTERRUPT_MS_QTY;
	// get ticks qty per 1ms
	double remainder = TCNT2/LPM_CLOCK_SMALL_TICKS_PER_1_MS;
	tmp += round(remainder); //add the remainder with rounding
	extern volatile unsigned long timer0_millis;
	timer0_millis += tmp;
}

void Lpm::stopClock() {
	TCCR2B=0; // No clock source (Timer/Counter stopped).
	TIMSK2=0; // disable interrupts
}

void Lpm::resetClock() {
	// disable interrupts
	TIMSK2 = 0;
	// set clock source to asynchronous
	ASSR = _BV(AS2);
	// set all registers
	TCNT2 = 0;
	OCR2A = 0;
	OCR2B = 0;
	TCCR2A = 0;
	TCCR2B = 0;
	// wait a bit
	delay(1);
	// clean flags
	TIFR2 = 0;
}
<|endoftext|>