<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "tools/ToolUtils.h"

#include <string>

#include "include/core/SkCanvas.h"
#include "include/core/SkFontMgr.h"
#include "include/core/SkGraphics.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTextBlob.h"
#include "include/core/SkTypeface.h"
#include "src/core/SkGlyphRun.h"
#include "tools/fonts/RandomScalerContext.h"

#ifdef SK_BUILD_FOR_WIN
    #include "include/ports/SkTypeface_win.h"
#endif

#include "tests/Test.h"

#include "include/gpu/GrContext.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/text/GrAtlasManager.h"

static void draw(SkCanvas* canvas, int redraw, const SkTArray<sk_sp<SkTextBlob>>& blobs) {
    int yOffset = 0;
    for (int r = 0; r < redraw; r++) {
        for (int i = 0; i < blobs.count(); i++) {
            const auto& blob = blobs[i];
            const SkRect& bounds = blob->bounds();
            yOffset += SkScalarCeilToInt(bounds.height());
            SkPaint paint;
            canvas->drawTextBlob(blob, 0, SkIntToScalar(yOffset), paint);
        }
    }
}

static const int kWidth = 1024;
static const int kHeight = 768;

static void setup_always_evict_atlas(GrContext* context) {
    context->priv().getAtlasManager()->setAtlasDimensionsToMinimum_ForTesting();
}

// This test hammers the GPU textblobcache and font atlas
static void text_blob_cache_inner(skiatest::Reporter* reporter, GrContext* context,
                                  int maxTotalText, int maxGlyphID, int maxFamilies, bool normal,
                                  bool stressTest) {
    // setup surface
    uint32_t flags = 0;
    SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);

    // configure our context for maximum stressing of cache and atlas
    if (stressTest) {
        setup_always_evict_atlas(context);
        context->priv().testingOnly_setTextBlobCacheLimit(0);
    }

    SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType,
                                         kPremul_SkAlphaType);
    auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, &props));
    REPORTER_ASSERT(reporter, surface);
    if (!surface) {
        return;
    }

    SkCanvas* canvas = surface->getCanvas();

    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());

    int count = std::min(fm->countFamilies(), maxFamilies);

    // make a ton of text
    SkAutoTArray<uint16_t> text(maxTotalText);
    for (int i = 0; i < maxTotalText; i++) {
        text[i] = i % maxGlyphID;
    }

    // generate textblobs
    SkTArray<sk_sp<SkTextBlob>> blobs;
    for (int i = 0; i < count; i++) {
        SkFont font;
        font.setSize(48); // draw big glyphs to really stress the atlas

        SkString familyName;
        fm->getFamilyName(i, &familyName);
        sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
        for (int j = 0; j < set->count(); ++j) {
            SkFontStyle fs;
            set->getStyle(j, &fs, nullptr);

            // We use a typeface which randomy returns unexpected mask formats to fuzz
            sk_sp<SkTypeface> orig(set->createTypeface(j));
            if (normal) {
                font.setTypeface(orig);
            } else {
                font.setTypeface(sk_make_sp<SkRandomTypeface>(orig, SkPaint(), true));
            }

            SkTextBlobBuilder builder;
            for (int aa = 0; aa < 2; aa++) {
                for (int subpixel = 0; subpixel < 2; subpixel++) {
                    for (int lcd = 0; lcd < 2; lcd++) {
                        font.setEdging(SkFont::Edging::kAlias);
                        if (aa) {
                            font.setEdging(SkFont::Edging::kAntiAlias);
                            if (lcd) {
                                font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
                            }
                        }
                        font.setSubpixel(SkToBool(subpixel));
                        if (!SkToBool(lcd)) {
                            font.setSize(160);
                        }
                        const SkTextBlobBuilder::RunBuffer& run = builder.allocRun(font,
                                                                                maxTotalText,
                                                                                0, 0,
                                                                                nullptr);
                        memcpy(run.glyphs, text.get(), maxTotalText * sizeof(uint16_t));
                    }
                }
            }
            blobs.emplace_back(builder.make());
        }
    }

    // create surface where LCD is impossible
    info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    SkSurfaceProps propsNoLCD(0, kUnknown_SkPixelGeometry);
    auto surfaceNoLCD(canvas->makeSurface(info, &propsNoLCD));
    REPORTER_ASSERT(reporter, surface);
    if (!surface) {
        return;
    }

    SkCanvas* canvasNoLCD = surfaceNoLCD->getCanvas();

    // test redraw
    draw(canvas, 2, blobs);
    draw(canvasNoLCD, 2, blobs);

    // test draw after free
    context->freeGpuResources();
    draw(canvas, 1, blobs);

    context->freeGpuResources();
    draw(canvasNoLCD, 1, blobs);

    // test draw after abandon
    context->abandonContext();
    draw(canvas, 1, blobs);
}

DEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobCache, reporter, ctxInfo) {
    text_blob_cache_inner(reporter, ctxInfo.grContext(), 1024, 256, 30, true, false);
}

DEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobStressCache, reporter, ctxInfo) {
    text_blob_cache_inner(reporter, ctxInfo.grContext(), 256, 256, 10, true, true);
}

DEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobAbnormal, reporter, ctxInfo) {
    text_blob_cache_inner(reporter, ctxInfo.grContext(), 256, 256, 10, false, false);
}

DEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobStressAbnormal, reporter, ctxInfo) {
    text_blob_cache_inner(reporter, ctxInfo.grContext(), 256, 256, 10, false, true);
}

static const int kScreenDim = 160;

static SkBitmap draw_blob(SkTextBlob* blob, SkSurface* surface, SkPoint offset) {

    SkPaint paint;

    SkCanvas* canvas = surface->getCanvas();
    canvas->save();
    canvas->drawColor(SK_ColorWHITE, SkBlendMode::kSrc);
    canvas->translate(offset.fX, offset.fY);
    canvas->drawTextBlob(blob, 0, 0, paint);
    SkBitmap bitmap;
    bitmap.allocN32Pixels(kScreenDim, kScreenDim);
    surface->readPixels(bitmap, 0, 0);
    canvas->restore();
    return bitmap;
}

static bool compare_bitmaps(const SkBitmap& expected, const SkBitmap& actual) {
    SkASSERT(expected.width() == actual.width());
    SkASSERT(expected.height() == actual.height());
    for (int i = 0; i < expected.width(); ++i) {
        for (int j = 0; j < expected.height(); ++j) {
            SkColor expectedColor = expected.getColor(i, j);
            SkColor actualColor = actual.getColor(i, j);
            if (expectedColor != actualColor) {
                return false;
            }
        }
    }
    return true;
}

static sk_sp<SkTextBlob> make_blob() {
    auto tf = SkTypeface::MakeFromName("Roboto2-Regular", SkFontStyle());
    SkFont font;
    font.setTypeface(tf);
    font.setSubpixel(false);
    font.setEdging(SkFont::Edging::kAlias);
    font.setSize(24);

    static char text[] = "HekpqB";
    static const int maxGlyphLen = sizeof(text) * 4;
    SkGlyphID glyphs[maxGlyphLen];
    int glyphCount =
            font.textToGlyphs(text, sizeof(text), SkTextEncoding::kUTF8, glyphs, maxGlyphLen);

    SkTextBlobBuilder builder;
    const auto& runBuffer = builder.allocRun(font, glyphCount, 0, 0);
    for (int i = 0; i < glyphCount; i++) {
        runBuffer.glyphs[i] = glyphs[i];
    }
    return builder.make();
}

static sk_sp<SkTextBlob> make_large_blob() {
    auto tf = SkTypeface::MakeFromName("Roboto2-Regular", SkFontStyle());
    SkFont font;
    font.setTypeface(tf);
    font.setSubpixel(false);
    font.setEdging(SkFont::Edging::kAlias);
    font.setSize(24);

    const int mallocSize = 0x3c3c3bd; // x86 size
    std::unique_ptr<char[]> text{new char[mallocSize + 1]};
    if (text == nullptr) {
        return nullptr;
    }
    for (int i = 0; i < mallocSize; i++) {
        text[i] = 'x';
    }
    text[mallocSize] = 0;

    static const int maxGlyphLen = mallocSize;
    std::unique_ptr<SkGlyphID[]> glyphs{new SkGlyphID[maxGlyphLen]};
    int glyphCount =
            font.textToGlyphs(
                    text.get(), mallocSize, SkTextEncoding::kUTF8, glyphs.get(), maxGlyphLen);
    SkTextBlobBuilder builder;
    const auto& runBuffer = builder.allocRun(font, glyphCount, 0, 0);
    for (int i = 0; i < glyphCount; i++) {
        runBuffer.glyphs[i] = glyphs[i];
    }
    return builder.make();
}

DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextBlobIntegerOverflowTest, reporter, ctxInfo) {
    auto grContext = ctxInfo.grContext();
    const SkImageInfo info =
            SkImageInfo::Make(kScreenDim, kScreenDim, kN32_SkColorType, kPremul_SkAlphaType);
    auto surface = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kNo, info);

    auto blob = make_large_blob();
    int y = 40;
    SkBitmap base = draw_blob(blob.get(), surface.get(), {40, y + 0.0f});
}

static const bool kDumpPngs = true;
// dump pngs needs a "good" and a "bad" directory to put the results in. This allows the use of the
// skdiff tool to visualize the differences.

void write_png(const std::string& filename, const SkBitmap& bitmap) {
    auto data = SkEncodeBitmap(bitmap, SkEncodedImageFormat::kPNG, 0);
    SkFILEWStream w{filename.c_str()};
    w.write(data->data(), data->size());
    w.fsync();
}

DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextBlobJaggedGlyph, reporter, ctxInfo) {
    auto grContext = ctxInfo.grContext();
    const SkImageInfo info =
            SkImageInfo::Make(kScreenDim, kScreenDim, kN32_SkColorType, kPremul_SkAlphaType);
    auto surface = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kNo, info);

    auto blob = make_blob();

    for (int y = 40; y < kScreenDim - 40; y++) {
        SkBitmap base = draw_blob(blob.get(), surface.get(), {40, y + 0.0f});
        SkBitmap half = draw_blob(blob.get(), surface.get(), {40, y + 0.5f});
        SkBitmap unit = draw_blob(blob.get(), surface.get(), {40, y + 1.0f});
        bool isOk = compare_bitmaps(base, half) || compare_bitmaps(unit, half);
        REPORTER_ASSERT(reporter, isOk);
        if (!isOk) {
            if (kDumpPngs) {
                {
                    std::string filename = "bad/half-y" + std::to_string(y) + ".png";
                    write_png(filename, half);
                }
                {
                    std::string filename = "good/half-y" + std::to_string(y) + ".png";
                    write_png(filename, base);
                }
            }
            break;
        }
    }

    // Testing the x direction across all platforms does not workout, because letter spacing can
    // change based on non-integer advance widths, but this has been useful for diagnosing problems.
#if 0
    blob = make_blob();
    for (int x = 40; x < kScreenDim - 40; x++) {
        SkBitmap base = draw_blob(blob.get(), surface.get(), {x + 0.0f, 40});
        SkBitmap half = draw_blob(blob.get(), surface.get(), {x + 0.5f, 40});
        SkBitmap unit = draw_blob(blob.get(), surface.get(), {x + 1.0f, 40});
        bool isOk = compare_bitmaps(base, half) || compare_bitmaps(unit, half);
        REPORTER_ASSERT(reporter, isOk);
        if (!isOk) {
            if (kDumpPngs) {
                {
                    std::string filename = "bad/half-x" + std::to_string(x) + ".png";
                    write_png(filename, half);
                }
                {
                    std::string filename = "good/half-x" + std::to_string(x) + ".png";
                    write_png(filename, base);
                }
            }
            break;
        }
    }
#endif
}

DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextBlobSmoothScroll, reporter, ctxInfo) {
    auto grContext = ctxInfo.grContext();
    const SkImageInfo info =
            SkImageInfo::Make(kScreenDim, kScreenDim, kN32_SkColorType, kPremul_SkAlphaType);
    auto surface = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kNo, info);

    auto movingBlob = make_blob();

    for (SkScalar y = 40; y < 50; y += 1.0/8.0) {
        auto expectedBlob = make_blob();
        auto expectedBitMap = draw_blob(expectedBlob.get(), surface.get(), {40, y});
        auto movingBitmap = draw_blob(movingBlob.get(), surface.get(), {40, y});
        bool isOk = compare_bitmaps(expectedBitMap, movingBitmap);
        REPORTER_ASSERT(reporter, isOk);
        if (!isOk) {
            if (kDumpPngs) {
                {
                    std::string filename = "bad/scroll-y" + std::to_string(y) + ".png";
                    write_png(filename, movingBitmap);
                }
                {
                    std::string filename = "good/scroll-y" + std::to_string(y) + ".png";
                    write_png(filename, expectedBitMap);
                }
            }
            break;
        }
    }
}
<commit_msg>turn off 2M glyph test<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "tools/ToolUtils.h"

#include <string>

#include "include/core/SkCanvas.h"
#include "include/core/SkFontMgr.h"
#include "include/core/SkGraphics.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTextBlob.h"
#include "include/core/SkTypeface.h"
#include "src/core/SkGlyphRun.h"
#include "tools/fonts/RandomScalerContext.h"

#ifdef SK_BUILD_FOR_WIN
    #include "include/ports/SkTypeface_win.h"
#endif

#include "tests/Test.h"

#include "include/gpu/GrContext.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/text/GrAtlasManager.h"

static void draw(SkCanvas* canvas, int redraw, const SkTArray<sk_sp<SkTextBlob>>& blobs) {
    int yOffset = 0;
    for (int r = 0; r < redraw; r++) {
        for (int i = 0; i < blobs.count(); i++) {
            const auto& blob = blobs[i];
            const SkRect& bounds = blob->bounds();
            yOffset += SkScalarCeilToInt(bounds.height());
            SkPaint paint;
            canvas->drawTextBlob(blob, 0, SkIntToScalar(yOffset), paint);
        }
    }
}

static const int kWidth = 1024;
static const int kHeight = 768;

static void setup_always_evict_atlas(GrContext* context) {
    context->priv().getAtlasManager()->setAtlasDimensionsToMinimum_ForTesting();
}

// This test hammers the GPU textblobcache and font atlas
static void text_blob_cache_inner(skiatest::Reporter* reporter, GrContext* context,
                                  int maxTotalText, int maxGlyphID, int maxFamilies, bool normal,
                                  bool stressTest) {
    // setup surface
    uint32_t flags = 0;
    SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);

    // configure our context for maximum stressing of cache and atlas
    if (stressTest) {
        setup_always_evict_atlas(context);
        context->priv().testingOnly_setTextBlobCacheLimit(0);
    }

    SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType,
                                         kPremul_SkAlphaType);
    auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, &props));
    REPORTER_ASSERT(reporter, surface);
    if (!surface) {
        return;
    }

    SkCanvas* canvas = surface->getCanvas();

    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());

    int count = std::min(fm->countFamilies(), maxFamilies);

    // make a ton of text
    SkAutoTArray<uint16_t> text(maxTotalText);
    for (int i = 0; i < maxTotalText; i++) {
        text[i] = i % maxGlyphID;
    }

    // generate textblobs
    SkTArray<sk_sp<SkTextBlob>> blobs;
    for (int i = 0; i < count; i++) {
        SkFont font;
        font.setSize(48); // draw big glyphs to really stress the atlas

        SkString familyName;
        fm->getFamilyName(i, &familyName);
        sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
        for (int j = 0; j < set->count(); ++j) {
            SkFontStyle fs;
            set->getStyle(j, &fs, nullptr);

            // We use a typeface which randomy returns unexpected mask formats to fuzz
            sk_sp<SkTypeface> orig(set->createTypeface(j));
            if (normal) {
                font.setTypeface(orig);
            } else {
                font.setTypeface(sk_make_sp<SkRandomTypeface>(orig, SkPaint(), true));
            }

            SkTextBlobBuilder builder;
            for (int aa = 0; aa < 2; aa++) {
                for (int subpixel = 0; subpixel < 2; subpixel++) {
                    for (int lcd = 0; lcd < 2; lcd++) {
                        font.setEdging(SkFont::Edging::kAlias);
                        if (aa) {
                            font.setEdging(SkFont::Edging::kAntiAlias);
                            if (lcd) {
                                font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
                            }
                        }
                        font.setSubpixel(SkToBool(subpixel));
                        if (!SkToBool(lcd)) {
                            font.setSize(160);
                        }
                        const SkTextBlobBuilder::RunBuffer& run = builder.allocRun(font,
                                                                                maxTotalText,
                                                                                0, 0,
                                                                                nullptr);
                        memcpy(run.glyphs, text.get(), maxTotalText * sizeof(uint16_t));
                    }
                }
            }
            blobs.emplace_back(builder.make());
        }
    }

    // create surface where LCD is impossible
    info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    SkSurfaceProps propsNoLCD(0, kUnknown_SkPixelGeometry);
    auto surfaceNoLCD(canvas->makeSurface(info, &propsNoLCD));
    REPORTER_ASSERT(reporter, surface);
    if (!surface) {
        return;
    }

    SkCanvas* canvasNoLCD = surfaceNoLCD->getCanvas();

    // test redraw
    draw(canvas, 2, blobs);
    draw(canvasNoLCD, 2, blobs);

    // test draw after free
    context->freeGpuResources();
    draw(canvas, 1, blobs);

    context->freeGpuResources();
    draw(canvasNoLCD, 1, blobs);

    // test draw after abandon
    context->abandonContext();
    draw(canvas, 1, blobs);
}

DEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobCache, reporter, ctxInfo) {
    text_blob_cache_inner(reporter, ctxInfo.grContext(), 1024, 256, 30, true, false);
}

DEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobStressCache, reporter, ctxInfo) {
    text_blob_cache_inner(reporter, ctxInfo.grContext(), 256, 256, 10, true, true);
}

DEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobAbnormal, reporter, ctxInfo) {
    text_blob_cache_inner(reporter, ctxInfo.grContext(), 256, 256, 10, false, false);
}

DEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobStressAbnormal, reporter, ctxInfo) {
    text_blob_cache_inner(reporter, ctxInfo.grContext(), 256, 256, 10, false, true);
}

static const int kScreenDim = 160;

static SkBitmap draw_blob(SkTextBlob* blob, SkSurface* surface, SkPoint offset) {

    SkPaint paint;

    SkCanvas* canvas = surface->getCanvas();
    canvas->save();
    canvas->drawColor(SK_ColorWHITE, SkBlendMode::kSrc);
    canvas->translate(offset.fX, offset.fY);
    canvas->drawTextBlob(blob, 0, 0, paint);
    SkBitmap bitmap;
    bitmap.allocN32Pixels(kScreenDim, kScreenDim);
    surface->readPixels(bitmap, 0, 0);
    canvas->restore();
    return bitmap;
}

static bool compare_bitmaps(const SkBitmap& expected, const SkBitmap& actual) {
    SkASSERT(expected.width() == actual.width());
    SkASSERT(expected.height() == actual.height());
    for (int i = 0; i < expected.width(); ++i) {
        for (int j = 0; j < expected.height(); ++j) {
            SkColor expectedColor = expected.getColor(i, j);
            SkColor actualColor = actual.getColor(i, j);
            if (expectedColor != actualColor) {
                return false;
            }
        }
    }
    return true;
}

static sk_sp<SkTextBlob> make_blob() {
    auto tf = SkTypeface::MakeFromName("Roboto2-Regular", SkFontStyle());
    SkFont font;
    font.setTypeface(tf);
    font.setSubpixel(false);
    font.setEdging(SkFont::Edging::kAlias);
    font.setSize(24);

    static char text[] = "HekpqB";
    static const int maxGlyphLen = sizeof(text) * 4;
    SkGlyphID glyphs[maxGlyphLen];
    int glyphCount =
            font.textToGlyphs(text, sizeof(text), SkTextEncoding::kUTF8, glyphs, maxGlyphLen);

    SkTextBlobBuilder builder;
    const auto& runBuffer = builder.allocRun(font, glyphCount, 0, 0);
    for (int i = 0; i < glyphCount; i++) {
        runBuffer.glyphs[i] = glyphs[i];
    }
    return builder.make();
}

// Turned off to pass on android and ios devices, which were running out of memory..
#if 0
static sk_sp<SkTextBlob> make_large_blob() {
    auto tf = SkTypeface::MakeFromName("Roboto2-Regular", SkFontStyle());
    SkFont font;
    font.setTypeface(tf);
    font.setSubpixel(false);
    font.setEdging(SkFont::Edging::kAlias);
    font.setSize(24);

    const int mallocSize = 0x3c3c3bd; // x86 size
    std::unique_ptr<char[]> text{new char[mallocSize + 1]};
    if (text == nullptr) {
        return nullptr;
    }
    for (int i = 0; i < mallocSize; i++) {
        text[i] = 'x';
    }
    text[mallocSize] = 0;

    static const int maxGlyphLen = mallocSize;
    std::unique_ptr<SkGlyphID[]> glyphs{new SkGlyphID[maxGlyphLen]};
    int glyphCount =
            font.textToGlyphs(
                    text.get(), mallocSize, SkTextEncoding::kUTF8, glyphs.get(), maxGlyphLen);
    SkTextBlobBuilder builder;
    const auto& runBuffer = builder.allocRun(font, glyphCount, 0, 0);
    for (int i = 0; i < glyphCount; i++) {
        runBuffer.glyphs[i] = glyphs[i];
    }
    return builder.make();
}

DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextBlobIntegerOverflowTest, reporter, ctxInfo) {
    auto grContext = ctxInfo.grContext();
    const SkImageInfo info =
            SkImageInfo::Make(kScreenDim, kScreenDim, kN32_SkColorType, kPremul_SkAlphaType);
    auto surface = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kNo, info);

    auto blob = make_large_blob();
    int y = 40;
    SkBitmap base = draw_blob(blob.get(), surface.get(), {40, y + 0.0f});
}
#endif

static const bool kDumpPngs = true;
// dump pngs needs a "good" and a "bad" directory to put the results in. This allows the use of the
// skdiff tool to visualize the differences.

void write_png(const std::string& filename, const SkBitmap& bitmap) {
    auto data = SkEncodeBitmap(bitmap, SkEncodedImageFormat::kPNG, 0);
    SkFILEWStream w{filename.c_str()};
    w.write(data->data(), data->size());
    w.fsync();
}

DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextBlobJaggedGlyph, reporter, ctxInfo) {
    auto grContext = ctxInfo.grContext();
    const SkImageInfo info =
            SkImageInfo::Make(kScreenDim, kScreenDim, kN32_SkColorType, kPremul_SkAlphaType);
    auto surface = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kNo, info);

    auto blob = make_blob();

    for (int y = 40; y < kScreenDim - 40; y++) {
        SkBitmap base = draw_blob(blob.get(), surface.get(), {40, y + 0.0f});
        SkBitmap half = draw_blob(blob.get(), surface.get(), {40, y + 0.5f});
        SkBitmap unit = draw_blob(blob.get(), surface.get(), {40, y + 1.0f});
        bool isOk = compare_bitmaps(base, half) || compare_bitmaps(unit, half);
        REPORTER_ASSERT(reporter, isOk);
        if (!isOk) {
            if (kDumpPngs) {
                {
                    std::string filename = "bad/half-y" + std::to_string(y) + ".png";
                    write_png(filename, half);
                }
                {
                    std::string filename = "good/half-y" + std::to_string(y) + ".png";
                    write_png(filename, base);
                }
            }
            break;
        }
    }

    // Testing the x direction across all platforms does not workout, because letter spacing can
    // change based on non-integer advance widths, but this has been useful for diagnosing problems.
#if 0
    blob = make_blob();
    for (int x = 40; x < kScreenDim - 40; x++) {
        SkBitmap base = draw_blob(blob.get(), surface.get(), {x + 0.0f, 40});
        SkBitmap half = draw_blob(blob.get(), surface.get(), {x + 0.5f, 40});
        SkBitmap unit = draw_blob(blob.get(), surface.get(), {x + 1.0f, 40});
        bool isOk = compare_bitmaps(base, half) || compare_bitmaps(unit, half);
        REPORTER_ASSERT(reporter, isOk);
        if (!isOk) {
            if (kDumpPngs) {
                {
                    std::string filename = "bad/half-x" + std::to_string(x) + ".png";
                    write_png(filename, half);
                }
                {
                    std::string filename = "good/half-x" + std::to_string(x) + ".png";
                    write_png(filename, base);
                }
            }
            break;
        }
    }
#endif
}

DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextBlobSmoothScroll, reporter, ctxInfo) {
    auto grContext = ctxInfo.grContext();
    const SkImageInfo info =
            SkImageInfo::Make(kScreenDim, kScreenDim, kN32_SkColorType, kPremul_SkAlphaType);
    auto surface = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kNo, info);

    auto movingBlob = make_blob();

    for (SkScalar y = 40; y < 50; y += 1.0/8.0) {
        auto expectedBlob = make_blob();
        auto expectedBitMap = draw_blob(expectedBlob.get(), surface.get(), {40, y});
        auto movingBitmap = draw_blob(movingBlob.get(), surface.get(), {40, y});
        bool isOk = compare_bitmaps(expectedBitMap, movingBitmap);
        REPORTER_ASSERT(reporter, isOk);
        if (!isOk) {
            if (kDumpPngs) {
                {
                    std::string filename = "bad/scroll-y" + std::to_string(y) + ".png";
                    write_png(filename, movingBitmap);
                }
                {
                    std::string filename = "good/scroll-y" + std::to_string(y) + ".png";
                    write_png(filename, expectedBitMap);
                }
            }
            break;
        }
    }
}
<|endoftext|>


<commit_before>/**
 * @author Koen Wolters <koen.wolters@cern.ch>
 * @author Mathieu Benoit <benoit@lal.in2p3.fr>
 */

#include "DepositionGeant4Module.hpp"

#include <limits>
#include <string>
#include <utility>

#include <G4HadronicProcessStore.hh>
#include <G4PhysListFactory.hh>
#include <G4RunManager.hh>
#include <G4StepLimiterPhysics.hh>
#include <G4UImanager.hh>
#include <G4UserLimits.hh>

#include "core/config/exceptions.h"
#include "core/geometry/GeometryManager.hpp"
#include "core/module/exceptions.h"
#include "core/utils/log.h"
#include "core/utils/random.h"
#include "tools/geant4.h"

#include "objects/DepositedCharge.hpp"

#include "GeneratorActionG4.hpp"
#include "SensitiveDetectorActionG4.hpp"

// FIXME: broken common includes
#include "modules/common/DetectorModelG4.hpp"

using namespace allpix;

DepositionGeant4Module::DepositionGeant4Module(Configuration config, Messenger* messenger, GeometryManager* geo_manager)
    : Module(config), config_(std::move(config)), messenger_(messenger), geo_manager_(geo_manager), last_event_num_(1),
      run_manager_g4_(nullptr) {
    // create user limits for maximum step length in the sensor
    user_limits_ =
        std::make_unique<G4UserLimits>(config_.get<double>("max_step_length", std::numeric_limits<double>::max()));
}

void DepositionGeant4Module::init() {
    // load the G4 run manager (which is currently owned by the geometry builder...)
    run_manager_g4_ = G4RunManager::GetRunManager();
    if(run_manager_g4_ == nullptr) {
        throw ModuleError("Cannot deposit charges using Geant4 without a Geant4 geometry builder");
    }

    // suppress all output for G4
    SUPPRESS_STREAM(G4cout);

    // find the physics list
    // FIXME: this is not on the correct place in the event / run logic
    // FIXME: set a good default physics list
    G4PhysListFactory physListFactory;
    G4VModularPhysicsList* physicsList = physListFactory.GetReferencePhysList(config_.get<std::string>("physics_list"));
    if(physicsList == nullptr) {
        RELEASE_STREAM(G4cout);
        // FIXME: more information about available lists
        throw InvalidValueError(config_, "physics_list", "specified physics list does not exists");
    }
    // register a step limiter
    physicsList->RegisterPhysics(new G4StepLimiterPhysics());
    // initialize the physics list
    LOG(TRACE) << "Initializing physics processes";
    run_manager_g4_->SetUserInitialization(physicsList);
    run_manager_g4_->InitializePhysics();

    // initialize the full run manager to ensure correct state flags
    run_manager_g4_->Initialize();

    // build generator
    LOG(TRACE) << "Constructing particle source";
    auto generator = new GeneratorActionG4(config_);
    run_manager_g4_->SetUserAction(generator);

    // get the creation energy for charge (default is silicon electron hole pair energy)
    // FIXME: is this a good name...
    auto charge_creation_energy = config_.get<double>("charge_creation_energy", 3.64e-6);

    // loop through all detectors and set the sensitive detector (call it action because that is what it is currently doing)
    bool useful_deposition = false;
    for(auto& detector : geo_manager_->getDetectors()) {
        // do not add sensitive detector for detectors that have no listeners
        if(!messenger_->hasReceiver(std::make_shared<DepositedChargeMessage>(std::vector<DepositedCharge>(), detector),
                                    "sensor")) {
            LOG(INFO) << "Not depositing charges in " << detector->getName()
                      << " because there is no listener for its output";
            continue;
        }
        useful_deposition = true;

        // get model of the detector
        auto model_g4 = detector->getExternalModel<DetectorModelG4>();

        // set maximum step length
        model_g4->pixel_log->SetUserLimits(user_limits_.get());

        // add the sensitive detector action
        auto sensitive_detector_action = new SensitiveDetectorActionG4(this, detector, messenger_, charge_creation_energy);
        model_g4->pixel_log->SetSensitiveDetector(sensitive_detector_action);
        sensors_.push_back(sensitive_detector_action);
    }

    if(!useful_deposition) {
        LOG(ERROR) << "Not a single listener for deposited charges, module is useless!";
    }

    // disable verbose processes
    // FIXME: there should be a more general way to do it, but I have not found it yet
    G4UImanager* UI = G4UImanager::GetUIpointer();
    UI->ApplyCommand("/process/verbose 0");
    UI->ApplyCommand("/process/em/verbose 0");
    UI->ApplyCommand("/process/eLoss/verbose 0");
    G4HadronicProcessStore::Instance()->SetVerbose(0);

    // set the seed
    std::string seed_command = "/random/setSeeds ";
    seed_command += std::to_string(static_cast<uint32_t>(get_random_seed() % UINT_MAX));
    seed_command += " ";
    seed_command += std::to_string(static_cast<uint32_t>(get_random_seed() % UINT_MAX));
    UI->ApplyCommand(seed_command);

    // release output from G4
    RELEASE_STREAM(G4cout);
}

// run the deposition
void DepositionGeant4Module::run(unsigned int event_num) {
    // suppress stream if not in debugging mode
    IFLOG(DEBUG);
    else {
        SUPPRESS_STREAM(G4cout);
    }

    // start the beam
    LOG(TRACE) << "Enabling beam";
    run_manager_g4_->BeamOn(1);
    last_event_num_ = event_num;

    // release the stream (if it was suspended)
    RELEASE_STREAM(G4cout);
}

// print summary
void DepositionGeant4Module::finalize() {
    size_t total_charges = 0;
    for(auto& sensor : sensors_) {
        total_charges += sensor->getTotalDepositedCharge();
    }

    if(sensors_.size() > 0 && total_charges > 0) {
        size_t average_charge = total_charges / sensors_.size() / last_event_num_;
        LOG(INFO) << "Deposited total of " << total_charges << " charges in " << sensors_.size() << " sensor(s) (average of "
                  << average_charge << " per sensor for every event)";
    } else {
        LOG(WARNING) << "No charges deposited";
    }
}
<commit_msg>change size to empty<commit_after>/**
 * @author Koen Wolters <koen.wolters@cern.ch>
 * @author Mathieu Benoit <benoit@lal.in2p3.fr>
 */

#include "DepositionGeant4Module.hpp"

#include <limits>
#include <string>
#include <utility>

#include <G4HadronicProcessStore.hh>
#include <G4PhysListFactory.hh>
#include <G4RunManager.hh>
#include <G4StepLimiterPhysics.hh>
#include <G4UImanager.hh>
#include <G4UserLimits.hh>

#include "core/config/exceptions.h"
#include "core/geometry/GeometryManager.hpp"
#include "core/module/exceptions.h"
#include "core/utils/log.h"
#include "core/utils/random.h"
#include "tools/geant4.h"

#include "objects/DepositedCharge.hpp"

#include "GeneratorActionG4.hpp"
#include "SensitiveDetectorActionG4.hpp"

// FIXME: broken common includes
#include "modules/common/DetectorModelG4.hpp"

using namespace allpix;

DepositionGeant4Module::DepositionGeant4Module(Configuration config, Messenger* messenger, GeometryManager* geo_manager)
    : Module(config), config_(std::move(config)), messenger_(messenger), geo_manager_(geo_manager), last_event_num_(1),
      run_manager_g4_(nullptr) {
    // create user limits for maximum step length in the sensor
    user_limits_ =
        std::make_unique<G4UserLimits>(config_.get<double>("max_step_length", std::numeric_limits<double>::max()));
}

void DepositionGeant4Module::init() {
    // load the G4 run manager (which is currently owned by the geometry builder...)
    run_manager_g4_ = G4RunManager::GetRunManager();
    if(run_manager_g4_ == nullptr) {
        throw ModuleError("Cannot deposit charges using Geant4 without a Geant4 geometry builder");
    }

    // suppress all output for G4
    SUPPRESS_STREAM(G4cout);

    // find the physics list
    // FIXME: this is not on the correct place in the event / run logic
    // FIXME: set a good default physics list
    G4PhysListFactory physListFactory;
    G4VModularPhysicsList* physicsList = physListFactory.GetReferencePhysList(config_.get<std::string>("physics_list"));
    if(physicsList == nullptr) {
        RELEASE_STREAM(G4cout);
        // FIXME: more information about available lists
        throw InvalidValueError(config_, "physics_list", "specified physics list does not exists");
    }
    // register a step limiter
    physicsList->RegisterPhysics(new G4StepLimiterPhysics());
    // initialize the physics list
    LOG(TRACE) << "Initializing physics processes";
    run_manager_g4_->SetUserInitialization(physicsList);
    run_manager_g4_->InitializePhysics();

    // initialize the full run manager to ensure correct state flags
    run_manager_g4_->Initialize();

    // build generator
    LOG(TRACE) << "Constructing particle source";
    auto generator = new GeneratorActionG4(config_);
    run_manager_g4_->SetUserAction(generator);

    // get the creation energy for charge (default is silicon electron hole pair energy)
    // FIXME: is this a good name...
    auto charge_creation_energy = config_.get<double>("charge_creation_energy", 3.64e-6);

    // loop through all detectors and set the sensitive detector (call it action because that is what it is currently doing)
    bool useful_deposition = false;
    for(auto& detector : geo_manager_->getDetectors()) {
        // do not add sensitive detector for detectors that have no listeners
        if(!messenger_->hasReceiver(std::make_shared<DepositedChargeMessage>(std::vector<DepositedCharge>(), detector),
                                    "sensor")) {
            LOG(INFO) << "Not depositing charges in " << detector->getName()
                      << " because there is no listener for its output";
            continue;
        }
        useful_deposition = true;

        // get model of the detector
        auto model_g4 = detector->getExternalModel<DetectorModelG4>();

        // set maximum step length
        model_g4->pixel_log->SetUserLimits(user_limits_.get());

        // add the sensitive detector action
        auto sensitive_detector_action = new SensitiveDetectorActionG4(this, detector, messenger_, charge_creation_energy);
        model_g4->pixel_log->SetSensitiveDetector(sensitive_detector_action);
        sensors_.push_back(sensitive_detector_action);
    }

    if(!useful_deposition) {
        LOG(ERROR) << "Not a single listener for deposited charges, module is useless!";
    }

    // disable verbose processes
    // FIXME: there should be a more general way to do it, but I have not found it yet
    G4UImanager* UI = G4UImanager::GetUIpointer();
    UI->ApplyCommand("/process/verbose 0");
    UI->ApplyCommand("/process/em/verbose 0");
    UI->ApplyCommand("/process/eLoss/verbose 0");
    G4HadronicProcessStore::Instance()->SetVerbose(0);

    // set the seed
    std::string seed_command = "/random/setSeeds ";
    seed_command += std::to_string(static_cast<uint32_t>(get_random_seed() % UINT_MAX));
    seed_command += " ";
    seed_command += std::to_string(static_cast<uint32_t>(get_random_seed() % UINT_MAX));
    UI->ApplyCommand(seed_command);

    // release output from G4
    RELEASE_STREAM(G4cout);
}

// run the deposition
void DepositionGeant4Module::run(unsigned int event_num) {
    // suppress stream if not in debugging mode
    IFLOG(DEBUG);
    else {
        SUPPRESS_STREAM(G4cout);
    }

    // start the beam
    LOG(TRACE) << "Enabling beam";
    run_manager_g4_->BeamOn(1);
    last_event_num_ = event_num;

    // release the stream (if it was suspended)
    RELEASE_STREAM(G4cout);
}

// print summary
void DepositionGeant4Module::finalize() {
    size_t total_charges = 0;
    for(auto& sensor : sensors_) {
        total_charges += sensor->getTotalDepositedCharge();
    }

    if(!sensors_.empty() && total_charges > 0) {
        size_t average_charge = total_charges / sensors_.size() / last_event_num_;
        LOG(INFO) << "Deposited total of " << total_charges << " charges in " << sensors_.size() << " sensor(s) (average of "
                  << average_charge << " per sensor for every event)";
    } else {
        LOG(WARNING) << "No charges deposited";
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <libport/bind.hh>
#include <libport/fcntl.h>
#include <libport/instrument.hh>
#include <libport/read-stdin.hh>
#include <libport/test.hh>

using libport::test_suite;

static void test_read_file()
{
  const std::string input = srcdir() + "/tests/libport/666.txt";
  BOOST_CHECK_EQUAL(libport::read_file(input), "666\n");
}

static void test_read_fd(const std::string& input)
{
  int fd = open(input.c_str(), O_RDONLY);
  BOOST_CHECK_NE(fd, -1);
  std::string content;
  try
  {
    while (true)
      content += libport::read_fd(fd);
  }
  catch (...)
  {}
  std::string reference = libport::read_file(input);
  BOOST_CHECK_EQUAL(reference.size(), content.size());
  BOOST_CHECK_EQUAL(reference, content);
}

test_suite*
init_test_suite()
{
  std::string short_file = srcdir() + "/tests/libport/666.txt";
  std::string long_file  = "Makefile";

  test_suite* suite = BOOST_TEST_SUITE("libport::read-stdin test suite");
  suite->add(BOOST_TEST_CASE(test_read_file));
  suite->add(BOOST_TEST_CASE(boost::bind(test_read_fd, short_file)));
  suite->add(BOOST_TEST_CASE(boost::bind(test_read_fd, long_file)));
  return suite;
}
<commit_msg>read-stdin: strengthen the test.<commit_after>/*
 * Copyright (C) 2009, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <libport/bind.hh>
#include <libport/fcntl.h>
#include <libport/instrument.hh>
#include <libport/read-stdin.hh>
#include <libport/test.hh>

using libport::test_suite;

static void test_read_file()
{
  const std::string input = srcdir() + "/tests/libport/666.txt";
  BOOST_CHECK_EQUAL(libport::read_file(input), "666\n");
}

static
std::string
file_content(const std::string& input)
{
  int fd = open(input.c_str(), O_RDONLY);
  BOOST_CHECK_NE(fd, -1);
  std::string content;
  try
  {
    while (true)
      content += libport::read_fd(fd);
  }
  catch (...)
  {}
  return content;
}

static void test_read_fd(const std::string& input)
{
  std::string reference = libport::read_file(input);
  std::string content = file_content(input);
  BOOST_CHECK_EQUAL(reference.size(), content.size());
  BOOST_CHECK_EQUAL(reference, content);
}

test_suite*
init_test_suite()
{
  std::string short_file = srcdir() + "/tests/libport/666.txt";
  std::string long_file  = "Makefile";

  test_suite* suite = BOOST_TEST_SUITE("libport::read-stdin test suite");
  suite->add(BOOST_TEST_CASE(test_read_file));
  suite->add(BOOST_TEST_CASE(boost::bind(test_read_fd, short_file)));
  // Make sure we can read the same file several times.
  suite->add(BOOST_TEST_CASE(boost::bind(test_read_fd, short_file)));
  suite->add(BOOST_TEST_CASE(boost::bind(test_read_fd, long_file)));
  return suite;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <seastar/core/thread.hh>
#include <seastar/tests/test-utils.hh>
#include <seastar/util/defer.hh>

#include "tests/cql_test_env.hh"
#include "tests/mutation_source_test.hh"
#include "tests/result_set_assertions.hh"
#include "service/migration_manager.hh"
#include "schema_builder.hh"

#include "disk-error-handler.hh"

thread_local disk_error_signal_type commit_error;
thread_local disk_error_signal_type general_disk_error;

SEASTAR_TEST_CASE(test_new_schema_with_no_structural_change_is_propagated) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            auto partial = schema_builder("tests", "table")
                    .with_column("pk", bytes_type, column_kind::partition_key)
                    .with_column("v1", bytes_type);

            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();

            auto old_schema = partial.build();

            service::get_local_migration_manager().announce_new_column_family(old_schema, false).get();

            auto old_table_version = e.db().local().find_schema(old_schema->id())->version();
            auto old_node_version = e.db().local().get_version();

            auto new_schema = partial.build();
            BOOST_REQUIRE_NE(new_schema->version(), old_schema->version());

            service::get_local_migration_manager().announce_column_family_update(new_schema, false, { }).get();

            BOOST_REQUIRE_NE(e.db().local().find_schema(old_schema->id())->version(), old_table_version);
            BOOST_REQUIRE_NE(e.db().local().get_version(), old_node_version);
        });
    });
}

SEASTAR_TEST_CASE(test_schema_is_updated_in_keyspace) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            auto builder = schema_builder("tests", "table")
                    .with_column("pk", bytes_type, column_kind::partition_key)
                    .with_column("ck", bytes_type, column_kind::clustering_key)
                    .with_column("v1", bytes_type);

            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();

            auto old_schema = builder.build();

            service::get_local_migration_manager().announce_new_column_family(old_schema, false).get();

            auto s = e.local_db().find_schema(old_schema->id());
            BOOST_REQUIRE_EQUAL(*old_schema, *s);
            BOOST_REQUIRE_EQUAL(864000, s->gc_grace_seconds().count());
            BOOST_REQUIRE_EQUAL(*s, *e.local_db().find_keyspace(s->ks_name()).metadata()->cf_meta_data().at(s->cf_name()));

            builder.set_gc_grace_seconds(1);
            auto new_schema = builder.build();

            service::get_local_migration_manager().announce_column_family_update(new_schema, false, { }).get();

            s = e.local_db().find_schema(old_schema->id());
            BOOST_REQUIRE_NE(*old_schema, *s);
            BOOST_REQUIRE_EQUAL(*new_schema, *s);
            BOOST_REQUIRE_EQUAL(1, s->gc_grace_seconds().count());
            BOOST_REQUIRE_EQUAL(*s, *e.local_db().find_keyspace(s->ks_name()).metadata()->cf_meta_data().at(s->cf_name()));
        });
    });
}

SEASTAR_TEST_CASE(test_tombstones_are_ignored_in_version_calculation) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();

            auto table_schema = schema_builder("ks", "table")
                    .with_column("pk", bytes_type, column_kind::partition_key)
                    .with_column("v1", bytes_type)
                    .build();

            service::get_local_migration_manager().announce_new_column_family(table_schema, false).get();

            auto old_table_version = e.db().local().find_schema(table_schema->id())->version();
            auto old_node_version = e.db().local().get_version();

            {
                BOOST_TEST_MESSAGE("Applying a no-op tombstone to v1 column definition");
                auto s = db::schema_tables::columns();
                auto pkey = partition_key::from_singular(*s, table_schema->ks_name());
                mutation m(pkey, s);
                auto ckey = clustering_key::from_exploded(*s, {utf8_type->decompose(table_schema->cf_name()), "v1"});
                m.partition().apply_delete(*s, ckey, tombstone(api::min_timestamp, gc_clock::now()));
                service::get_local_migration_manager().announce(std::vector<mutation>({m}), true).get();
            }

            auto new_table_version = e.db().local().find_schema(table_schema->id())->version();
            auto new_node_version = e.db().local().get_version();

            BOOST_REQUIRE_EQUAL(new_table_version, old_table_version);
            BOOST_REQUIRE_EQUAL(new_node_version, old_node_version);
        });
    });
}

SEASTAR_TEST_CASE(test_column_is_dropped) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();
            e.execute_cql("create table tests.table1 (pk int primary key, c1 int, c2 int);").get();
            e.execute_cql("alter table tests.table1 drop c2;").get();
            e.execute_cql("alter table tests.table1 add s1 int;").get();

            schema_ptr s = e.db().local().find_schema("tests", "table1");
            BOOST_REQUIRE(s->columns_by_name().count(to_bytes("c1")));
            BOOST_REQUIRE(!s->columns_by_name().count(to_bytes("c2")));
            BOOST_REQUIRE(s->columns_by_name().count(to_bytes("s1")));
        });
    });
}

class counting_migration_listener : public service::migration_listener {
public:
    int create_keyspace_count = 0;
    int create_column_family_count = 0;
    int create_user_type_count = 0;
    int create_function_count = 0;
    int create_aggregate_count = 0;
    int create_view_count = 0;
    int update_keyspace_count = 0;
    int update_column_family_count = 0;
    int columns_changed_count = 0;
    int update_user_type_count = 0;
    int update_function_count = 0;
    int update_aggregate_count = 0;
    int update_view_count = 0;
    int drop_keyspace_count = 0;
    int drop_column_family_count = 0;
    int drop_user_type_count = 0;
    int drop_function_count = 0;
    int drop_aggregate_count = 0;
    int drop_view_count = 0;
public:
    virtual void on_create_keyspace(const sstring&) override { ++create_keyspace_count; }
    virtual void on_create_column_family(const sstring&, const sstring&) override { ++create_column_family_count; }
    virtual void on_create_user_type(const sstring&, const sstring&) override { ++create_user_type_count; }
    virtual void on_create_function(const sstring&, const sstring&) override { ++create_function_count; }
    virtual void on_create_aggregate(const sstring&, const sstring&) override { ++create_aggregate_count; }
    virtual void on_create_view(const sstring&, const sstring&) override { ++create_view_count; }
    virtual void on_update_keyspace(const sstring&) override { ++update_keyspace_count; }
    virtual void on_update_column_family(const sstring&, const sstring&, bool columns_changed) override {
        ++update_column_family_count;
        columns_changed_count += int(columns_changed);
    }
    virtual void on_update_user_type(const sstring&, const sstring&) override { ++update_user_type_count; }
    virtual void on_update_function(const sstring&, const sstring&) override { ++update_function_count; }
    virtual void on_update_aggregate(const sstring&, const sstring&) override { ++update_aggregate_count; }
    virtual void on_update_view(const sstring&, const sstring&, bool) override { ++update_view_count; }
    virtual void on_drop_keyspace(const sstring&) override { ++drop_keyspace_count; }
    virtual void on_drop_column_family(const sstring&, const sstring&) override { ++drop_column_family_count; }
    virtual void on_drop_user_type(const sstring&, const sstring&) override { ++drop_user_type_count; }
    virtual void on_drop_function(const sstring&, const sstring&) override { ++drop_function_count; }
    virtual void on_drop_aggregate(const sstring&, const sstring&) override { ++drop_aggregate_count; }
    virtual void on_drop_view(const sstring&, const sstring&) override { ++drop_view_count; }
};

SEASTAR_TEST_CASE(test_notifications) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            counting_migration_listener listener;
            service::get_local_migration_manager().register_listener(&listener);
            auto listener_lease = defer([&listener] { service::get_local_migration_manager().register_listener(&listener); });

            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();

            BOOST_REQUIRE_EQUAL(listener.create_keyspace_count, 1);

            e.execute_cql("create table tests.table1 (pk int primary key, c1 int, c2 int);").get();

            BOOST_REQUIRE_EQUAL(listener.create_column_family_count, 1);
            BOOST_REQUIRE_EQUAL(listener.columns_changed_count, 0);

            e.execute_cql("alter table tests.table1 drop c2;").get();

            BOOST_REQUIRE_EQUAL(listener.update_column_family_count, 1);
            BOOST_REQUIRE_EQUAL(listener.columns_changed_count, 1);

            e.execute_cql("alter table tests.table1 add s1 int;").get();

            BOOST_REQUIRE_EQUAL(listener.update_column_family_count, 2);
            BOOST_REQUIRE_EQUAL(listener.columns_changed_count, 2);

            e.execute_cql("alter table tests.table1 alter s1 type blob;").get();

            BOOST_REQUIRE_EQUAL(listener.update_column_family_count, 3);
            BOOST_REQUIRE_EQUAL(listener.columns_changed_count, 3);

            e.execute_cql("drop table tests.table1;").get();

            BOOST_REQUIRE_EQUAL(listener.drop_column_family_count, 1);

            e.execute_cql("create type tests.type1 (field1 text, field2 text);").get();

            BOOST_REQUIRE_EQUAL(listener.create_user_type_count, 1);

            e.execute_cql("drop type tests.type1;").get();

            BOOST_REQUIRE_EQUAL(listener.drop_user_type_count, 1);

            e.execute_cql("create type tests.type1 (field1 text, field2 text);").get();
            e.execute_cql("create type tests.type2 (field1 text, field2 text);").get();

            BOOST_REQUIRE_EQUAL(listener.create_user_type_count, 3);

            e.execute_cql("drop type tests.type1;").get();

            BOOST_REQUIRE_EQUAL(listener.drop_user_type_count, 2);

            e.execute_cql("alter type tests.type2 add field3 text;").get();

            BOOST_REQUIRE_EQUAL(listener.update_user_type_count, 1);

            e.execute_cql("alter type tests.type2 alter field3 type blob;").get();

            BOOST_REQUIRE_EQUAL(listener.update_user_type_count, 2);

            e.execute_cql("alter type tests.type2 rename field2 to field4 and field3 to field5;").get();

            BOOST_REQUIRE_EQUAL(listener.update_user_type_count, 3);
        });
    });
}

SEASTAR_TEST_CASE(test_prepared_statement_is_invalidated_by_schema_change) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            logging::logger_registry().set_logger_level("query_processor", logging::log_level::debug);
            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();
            e.execute_cql("create table tests.table1 (pk int primary key, c1 int, c2 int);").get();
            bytes id = e.prepare("select * from tests.table1;").get0();

            e.execute_cql("alter table tests.table1 add s1 int;").get();

            try {
                e.execute_prepared(id, {}).get();
                BOOST_FAIL("Should have failed");
            } catch (const not_prepared_exception&) {
                // expected
            }
        });
    });
}
<commit_msg>tests: Add test for concurrent column addition<commit_after>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <seastar/core/thread.hh>
#include <seastar/tests/test-utils.hh>
#include <seastar/util/defer.hh>

#include "tests/cql_test_env.hh"
#include "tests/mutation_source_test.hh"
#include "tests/result_set_assertions.hh"
#include "service/migration_manager.hh"
#include "schema_builder.hh"

#include "disk-error-handler.hh"

thread_local disk_error_signal_type commit_error;
thread_local disk_error_signal_type general_disk_error;

SEASTAR_TEST_CASE(test_new_schema_with_no_structural_change_is_propagated) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            auto partial = schema_builder("tests", "table")
                    .with_column("pk", bytes_type, column_kind::partition_key)
                    .with_column("v1", bytes_type);

            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();

            auto old_schema = partial.build();

            service::get_local_migration_manager().announce_new_column_family(old_schema, false).get();

            auto old_table_version = e.db().local().find_schema(old_schema->id())->version();
            auto old_node_version = e.db().local().get_version();

            auto new_schema = partial.build();
            BOOST_REQUIRE_NE(new_schema->version(), old_schema->version());

            service::get_local_migration_manager().announce_column_family_update(new_schema, false, { }).get();

            BOOST_REQUIRE_NE(e.db().local().find_schema(old_schema->id())->version(), old_table_version);
            BOOST_REQUIRE_NE(e.db().local().get_version(), old_node_version);
        });
    });
}

SEASTAR_TEST_CASE(test_schema_is_updated_in_keyspace) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            auto builder = schema_builder("tests", "table")
                    .with_column("pk", bytes_type, column_kind::partition_key)
                    .with_column("ck", bytes_type, column_kind::clustering_key)
                    .with_column("v1", bytes_type);

            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();

            auto old_schema = builder.build();

            service::get_local_migration_manager().announce_new_column_family(old_schema, false).get();

            auto s = e.local_db().find_schema(old_schema->id());
            BOOST_REQUIRE_EQUAL(*old_schema, *s);
            BOOST_REQUIRE_EQUAL(864000, s->gc_grace_seconds().count());
            BOOST_REQUIRE_EQUAL(*s, *e.local_db().find_keyspace(s->ks_name()).metadata()->cf_meta_data().at(s->cf_name()));

            builder.set_gc_grace_seconds(1);
            auto new_schema = builder.build();

            service::get_local_migration_manager().announce_column_family_update(new_schema, false, { }).get();

            s = e.local_db().find_schema(old_schema->id());
            BOOST_REQUIRE_NE(*old_schema, *s);
            BOOST_REQUIRE_EQUAL(*new_schema, *s);
            BOOST_REQUIRE_EQUAL(1, s->gc_grace_seconds().count());
            BOOST_REQUIRE_EQUAL(*s, *e.local_db().find_keyspace(s->ks_name()).metadata()->cf_meta_data().at(s->cf_name()));
        });
    });
}

SEASTAR_TEST_CASE(test_tombstones_are_ignored_in_version_calculation) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();

            auto table_schema = schema_builder("ks", "table")
                    .with_column("pk", bytes_type, column_kind::partition_key)
                    .with_column("v1", bytes_type)
                    .build();

            service::get_local_migration_manager().announce_new_column_family(table_schema, false).get();

            auto old_table_version = e.db().local().find_schema(table_schema->id())->version();
            auto old_node_version = e.db().local().get_version();

            {
                BOOST_TEST_MESSAGE("Applying a no-op tombstone to v1 column definition");
                auto s = db::schema_tables::columns();
                auto pkey = partition_key::from_singular(*s, table_schema->ks_name());
                mutation m(pkey, s);
                auto ckey = clustering_key::from_exploded(*s, {utf8_type->decompose(table_schema->cf_name()), "v1"});
                m.partition().apply_delete(*s, ckey, tombstone(api::min_timestamp, gc_clock::now()));
                service::get_local_migration_manager().announce(std::vector<mutation>({m}), true).get();
            }

            auto new_table_version = e.db().local().find_schema(table_schema->id())->version();
            auto new_node_version = e.db().local().get_version();

            BOOST_REQUIRE_EQUAL(new_table_version, old_table_version);
            BOOST_REQUIRE_EQUAL(new_node_version, old_node_version);
        });
    });
}

SEASTAR_TEST_CASE(test_concurrent_column_addition) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();

            service::migration_manager& mm = service::get_local_migration_manager();

            auto s0 = schema_builder("ks", "table")
                    .with_column("pk", bytes_type, column_kind::partition_key)
                    .with_column("v1", bytes_type)
                    .build();

            auto s1 = schema_builder("ks", "table")
                    .with_column("pk", bytes_type, column_kind::partition_key)
                    .with_column("v1", bytes_type)
                    .with_column("v3", bytes_type)
                    .build();

            auto s2 = schema_builder("ks", "table", stdx::make_optional(s1->id()))
                    .with_column("pk", bytes_type, column_kind::partition_key)
                    .with_column("v1", bytes_type)
                    .with_column("v2", bytes_type)
                    .build();

            mm.announce_new_column_family(s1, false).get();
            auto old_version = e.db().local().find_schema(s1->id())->version();

            // Apply s0 -> s2 change.
            {
                auto&& keyspace = e.db().local().find_keyspace(s0->ks_name()).metadata();
                auto muts = db::schema_tables::make_update_table_mutations(keyspace, s0, s2,
                    api::new_timestamp(), false).get0();
                mm.announce(std::move(muts), true).get();
            }

            auto new_schema = e.db().local().find_schema(s1->id());

            BOOST_REQUIRE(new_schema->get_column_definition(to_bytes("v1")) != nullptr);
            BOOST_REQUIRE(new_schema->get_column_definition(to_bytes("v2")) != nullptr);
            BOOST_REQUIRE(new_schema->get_column_definition(to_bytes("v3")) != nullptr);

            BOOST_REQUIRE(new_schema->version() != old_version);
            BOOST_REQUIRE(new_schema->version() != s2->version());
        });
    });
}

SEASTAR_TEST_CASE(test_column_is_dropped) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();
            e.execute_cql("create table tests.table1 (pk int primary key, c1 int, c2 int);").get();
            e.execute_cql("alter table tests.table1 drop c2;").get();
            e.execute_cql("alter table tests.table1 add s1 int;").get();

            schema_ptr s = e.db().local().find_schema("tests", "table1");
            BOOST_REQUIRE(s->columns_by_name().count(to_bytes("c1")));
            BOOST_REQUIRE(!s->columns_by_name().count(to_bytes("c2")));
            BOOST_REQUIRE(s->columns_by_name().count(to_bytes("s1")));
        });
    });
}

class counting_migration_listener : public service::migration_listener {
public:
    int create_keyspace_count = 0;
    int create_column_family_count = 0;
    int create_user_type_count = 0;
    int create_function_count = 0;
    int create_aggregate_count = 0;
    int create_view_count = 0;
    int update_keyspace_count = 0;
    int update_column_family_count = 0;
    int columns_changed_count = 0;
    int update_user_type_count = 0;
    int update_function_count = 0;
    int update_aggregate_count = 0;
    int update_view_count = 0;
    int drop_keyspace_count = 0;
    int drop_column_family_count = 0;
    int drop_user_type_count = 0;
    int drop_function_count = 0;
    int drop_aggregate_count = 0;
    int drop_view_count = 0;
public:
    virtual void on_create_keyspace(const sstring&) override { ++create_keyspace_count; }
    virtual void on_create_column_family(const sstring&, const sstring&) override { ++create_column_family_count; }
    virtual void on_create_user_type(const sstring&, const sstring&) override { ++create_user_type_count; }
    virtual void on_create_function(const sstring&, const sstring&) override { ++create_function_count; }
    virtual void on_create_aggregate(const sstring&, const sstring&) override { ++create_aggregate_count; }
    virtual void on_create_view(const sstring&, const sstring&) override { ++create_view_count; }
    virtual void on_update_keyspace(const sstring&) override { ++update_keyspace_count; }
    virtual void on_update_column_family(const sstring&, const sstring&, bool columns_changed) override {
        ++update_column_family_count;
        columns_changed_count += int(columns_changed);
    }
    virtual void on_update_user_type(const sstring&, const sstring&) override { ++update_user_type_count; }
    virtual void on_update_function(const sstring&, const sstring&) override { ++update_function_count; }
    virtual void on_update_aggregate(const sstring&, const sstring&) override { ++update_aggregate_count; }
    virtual void on_update_view(const sstring&, const sstring&, bool) override { ++update_view_count; }
    virtual void on_drop_keyspace(const sstring&) override { ++drop_keyspace_count; }
    virtual void on_drop_column_family(const sstring&, const sstring&) override { ++drop_column_family_count; }
    virtual void on_drop_user_type(const sstring&, const sstring&) override { ++drop_user_type_count; }
    virtual void on_drop_function(const sstring&, const sstring&) override { ++drop_function_count; }
    virtual void on_drop_aggregate(const sstring&, const sstring&) override { ++drop_aggregate_count; }
    virtual void on_drop_view(const sstring&, const sstring&) override { ++drop_view_count; }
};

SEASTAR_TEST_CASE(test_notifications) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            counting_migration_listener listener;
            service::get_local_migration_manager().register_listener(&listener);
            auto listener_lease = defer([&listener] { service::get_local_migration_manager().register_listener(&listener); });

            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();

            BOOST_REQUIRE_EQUAL(listener.create_keyspace_count, 1);

            e.execute_cql("create table tests.table1 (pk int primary key, c1 int, c2 int);").get();

            BOOST_REQUIRE_EQUAL(listener.create_column_family_count, 1);
            BOOST_REQUIRE_EQUAL(listener.columns_changed_count, 0);

            e.execute_cql("alter table tests.table1 drop c2;").get();

            BOOST_REQUIRE_EQUAL(listener.update_column_family_count, 1);
            BOOST_REQUIRE_EQUAL(listener.columns_changed_count, 1);

            e.execute_cql("alter table tests.table1 add s1 int;").get();

            BOOST_REQUIRE_EQUAL(listener.update_column_family_count, 2);
            BOOST_REQUIRE_EQUAL(listener.columns_changed_count, 2);

            e.execute_cql("alter table tests.table1 alter s1 type blob;").get();

            BOOST_REQUIRE_EQUAL(listener.update_column_family_count, 3);
            BOOST_REQUIRE_EQUAL(listener.columns_changed_count, 3);

            e.execute_cql("drop table tests.table1;").get();

            BOOST_REQUIRE_EQUAL(listener.drop_column_family_count, 1);

            e.execute_cql("create type tests.type1 (field1 text, field2 text);").get();

            BOOST_REQUIRE_EQUAL(listener.create_user_type_count, 1);

            e.execute_cql("drop type tests.type1;").get();

            BOOST_REQUIRE_EQUAL(listener.drop_user_type_count, 1);

            e.execute_cql("create type tests.type1 (field1 text, field2 text);").get();
            e.execute_cql("create type tests.type2 (field1 text, field2 text);").get();

            BOOST_REQUIRE_EQUAL(listener.create_user_type_count, 3);

            e.execute_cql("drop type tests.type1;").get();

            BOOST_REQUIRE_EQUAL(listener.drop_user_type_count, 2);

            e.execute_cql("alter type tests.type2 add field3 text;").get();

            BOOST_REQUIRE_EQUAL(listener.update_user_type_count, 1);

            e.execute_cql("alter type tests.type2 alter field3 type blob;").get();

            BOOST_REQUIRE_EQUAL(listener.update_user_type_count, 2);

            e.execute_cql("alter type tests.type2 rename field2 to field4 and field3 to field5;").get();

            BOOST_REQUIRE_EQUAL(listener.update_user_type_count, 3);
        });
    });
}

SEASTAR_TEST_CASE(test_prepared_statement_is_invalidated_by_schema_change) {
    return do_with_cql_env([](cql_test_env& e) {
        return seastar::async([&] {
            logging::logger_registry().set_logger_level("query_processor", logging::log_level::debug);
            e.execute_cql("create keyspace tests with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").get();
            e.execute_cql("create table tests.table1 (pk int primary key, c1 int, c2 int);").get();
            bytes id = e.prepare("select * from tests.table1;").get0();

            e.execute_cql("alter table tests.table1 add s1 int;").get();

            try {
                e.execute_prepared(id, {}).get();
                BOOST_FAIL("Should have failed");
            } catch (const not_prepared_exception&) {
                // expected
            }
        });
    });
}
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2013 Soumyajit De
 */

#include <shogun/lib/common.h>

#ifdef HAVE_EIGEN3
#include <shogun/mathematics/eigen3.h>
#include <shogun/mathematics/Statistics.h>
#include <shogun/lib/SGVector.h>
#include <shogun/lib/SGMatrix.h>
#include <shogun/mathematics/logdet/DenseMatrixOperator.h>
#include <shogun/mathematics/logdet/DenseMatrixExactLog.h>
#include <shogun/mathematics/logdet/LogRationalApproximationIndividual.h>
#include <shogun/mathematics/logdet/NormalSampler.h>
#include <shogun/mathematics/logdet/DirectEigenSolver.h>
#include <shogun/mathematics/logdet/DirectLinearSolverComplex.h>
#include <shogun/mathematics/logdet/LogDetEstimator.h>
#include <shogun/lib/computation/job/ScalarResult.h>
#include <shogun/lib/computation/engine/SerialComputationEngine.h>
#include <gtest/gtest.h>

using namespace shogun;

#if EIGEN_VERSION_AT_LEAST(3,1,0)
TEST(LogDetEstimator, sample)
{
	CSerialComputationEngine* e=new CSerialComputationEngine;
	SG_REF(e);

	const index_t size=2;
	SGMatrix<float64_t> mat(size, size);
	mat(0,0)=2.0;
	mat(0,1)=1.0;
	mat(1,0)=1.0;
	mat(1,1)=3.0;

	CDenseMatrixOperator<float64_t, float64_t>* op=new CDenseMatrixOperator<float64_t, float64_t>(mat);
	SG_REF(op);

	CDenseMatrixExactLog *op_func=new CDenseMatrixExactLog(op, e);
	SG_REF(op_func);

	CNormalSampler* trace_sampler=new CNormalSampler(size);
	SG_REF(trace_sampler);

	CLogDetEstimator estimator(trace_sampler, op_func, e);
	const index_t num_estimates=5000;
	SGVector<float64_t> estimates=estimator.sample(num_estimates);

	float64_t result=0.0;
	for (index_t i=0; i<num_estimates; ++i)
		result+=estimates[i];
	result/=num_estimates;

	EXPECT_NEAR(result, 1.60943791243410050384, 0.1);

	SG_UNREF(trace_sampler);
	SG_UNREF(op_func);
	SG_UNREF(op);
	SG_UNREF(e);
}
#endif // EIGEN_VERSION_AT_LEAST(3,1,0)

TEST(LogDetEstimator, sample_ratapp)
{
	CSerialComputationEngine* e=new CSerialComputationEngine;
	SG_REF(e);

	const index_t size=2;
	SGMatrix<float64_t> mat(size, size);
	mat(0,0)=1.0;
	mat(0,1)=0.5;
	mat(1,0)=0.5;
	mat(1,1)=1000.0;

	CDenseMatrixOperator<float64_t, float64_t>* op=new CDenseMatrixOperator<float64_t, float64_t>(mat);
	SG_REF(op);

	CDirectEigenSolver* eig_solver=new CDirectEigenSolver(op);
	SG_REF(eig_solver);

	CDirectLinearSolverComplex* linear_solver=new CDirectLinearSolverComplex();
	SG_REF(linear_solver);

	CLogRationalApproximationIndividual *op_func
		=new CLogRationalApproximationIndividual(
			op, e, eig_solver, (CLinearSolver<complex64_t, float64_t>*)linear_solver, 8);
	SG_REF(op_func);

	CNormalSampler* trace_sampler=new CNormalSampler(size);
	SG_REF(trace_sampler);

	CLogDetEstimator estimator(trace_sampler, op_func, e);
	const index_t num_estimates=5000;
	SGVector<float64_t> estimates=estimator.sample(num_estimates);

	float64_t result=0.0;
	for (index_t i=0; i<num_estimates; ++i)
		result+=estimates[i];
	result/=num_estimates;

	EXPECT_NEAR(result, CStatistics::log_det(mat), 0.35);

	SG_UNREF(trace_sampler);
	SG_UNREF(eig_solver);
	SG_UNREF(linear_solver);
	SG_UNREF(op_func);
	SG_UNREF(op);
	SG_UNREF(e);
}

#endif // HAVE_EIGEN3

<commit_msg>reduced time and accuracy for log-det estimator unit-test<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2013 Soumyajit De
 */

#include <shogun/lib/common.h>

#ifdef HAVE_EIGEN3
#include <shogun/mathematics/eigen3.h>
#include <shogun/mathematics/Statistics.h>
#include <shogun/lib/SGVector.h>
#include <shogun/lib/SGMatrix.h>
#include <shogun/mathematics/logdet/DenseMatrixOperator.h>
#include <shogun/mathematics/logdet/DenseMatrixExactLog.h>
#include <shogun/mathematics/logdet/LogRationalApproximationIndividual.h>
#include <shogun/mathematics/logdet/NormalSampler.h>
#include <shogun/mathematics/logdet/DirectEigenSolver.h>
#include <shogun/mathematics/logdet/DirectLinearSolverComplex.h>
#include <shogun/mathematics/logdet/LogDetEstimator.h>
#include <shogun/lib/computation/job/ScalarResult.h>
#include <shogun/lib/computation/engine/SerialComputationEngine.h>
#include <gtest/gtest.h>

using namespace shogun;

#if EIGEN_VERSION_AT_LEAST(3,1,0)
TEST(LogDetEstimator, sample)
{
	CSerialComputationEngine* e=new CSerialComputationEngine;
	SG_REF(e);

	const index_t size=2;
	SGMatrix<float64_t> mat(size, size);
	mat(0,0)=2.0;
	mat(0,1)=1.0;
	mat(1,0)=1.0;
	mat(1,1)=3.0;

	CDenseMatrixOperator<float64_t, float64_t>* op=new CDenseMatrixOperator<float64_t, float64_t>(mat);
	SG_REF(op);

	CDenseMatrixExactLog *op_func=new CDenseMatrixExactLog(op, e);
	SG_REF(op_func);

	CNormalSampler* trace_sampler=new CNormalSampler(size);
	SG_REF(trace_sampler);

	CLogDetEstimator estimator(trace_sampler, op_func, e);
	const index_t num_estimates=5000;
	SGVector<float64_t> estimates=estimator.sample(num_estimates);

	float64_t result=0.0;
	for (index_t i=0; i<num_estimates; ++i)
		result+=estimates[i];
	result/=num_estimates;

	EXPECT_NEAR(result, 1.60943791243410050384, 0.1);

	SG_UNREF(trace_sampler);
	SG_UNREF(op_func);
	SG_UNREF(op);
	SG_UNREF(e);
}
#endif // EIGEN_VERSION_AT_LEAST(3,1,0)

TEST(LogDetEstimator, sample_ratapp)
{
	CSerialComputationEngine* e=new CSerialComputationEngine;
	SG_REF(e);

	const index_t size=2;
	SGMatrix<float64_t> mat(size, size);
	mat(0,0)=1.0;
	mat(0,1)=0.5;
	mat(1,0)=0.5;
	mat(1,1)=1000.0;

	CDenseMatrixOperator<float64_t, float64_t>* op=new CDenseMatrixOperator<float64_t, float64_t>(mat);
	SG_REF(op);

	CDirectEigenSolver* eig_solver=new CDirectEigenSolver(op);
	SG_REF(eig_solver);

	CDirectLinearSolverComplex* linear_solver=new CDirectLinearSolverComplex();
	SG_REF(linear_solver);

	CLogRationalApproximationIndividual *op_func
		=new CLogRationalApproximationIndividual(
			op, e, eig_solver, (CLinearSolver<complex64_t, float64_t>*)linear_solver, 8);
	SG_REF(op_func);

	CNormalSampler* trace_sampler=new CNormalSampler(size);
	SG_REF(trace_sampler);

	CLogDetEstimator estimator(trace_sampler, op_func, e);
	const index_t num_estimates=500;
	SGVector<float64_t> estimates=estimator.sample(num_estimates);

	float64_t result=0.0;
	for (index_t i=0; i<num_estimates; ++i)
		result+=estimates[i];
	result/=num_estimates;

	EXPECT_NEAR(result, CStatistics::log_det(mat), 0.5);

	SG_UNREF(trace_sampler);
	SG_UNREF(eig_solver);
	SG_UNREF(linear_solver);
	SG_UNREF(op_func);
	SG_UNREF(op);
	SG_UNREF(e);
}

#endif // HAVE_EIGEN3

<|endoftext|>


<commit_before>//============================================================================
// Name        : brainfuck_rpc_emulator.cpp
// Author      : Artem Kashkanov
// Version     :
// Copyright   :
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <iomanip>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <cstring>

#include "Console.h"

#include "Image.h"
#include <fstream>

#include <vector>

#include "bfutils.h"

using namespace std;

bool ProtectedModeEnabled = false;

void SetProtectedMode(bool mode){
     ProtectedModeEnabled = mode;
}

bool GetProtectedMode(void){
     return ProtectedModeEnabled;
}
//Set 16-bit word mode:
bool WordModeEnabled = false;

void SetWordMode(bool mode){
     WordModeEnabled = mode;
}

bool GetWordMode(void){
     return WordModeEnabled;
}

uint8_t ExecCmd(Image &image, uint16_t *MemoryPtr, uint16_t &IP, uint16_t &AP){
	uint8_t status = SUCCESS;
	uint16_t cmd = MemoryPtr[IP];
	uint16_t cmd_bin = ((cmd>>13) & 0x0007);
	bool sign = ((cmd >> 12)&0x01)? true: false;
	uint16_t bias = (cmd&0x0FFF);
	switch (cmd_bin){
	case 0:// '<' and '>' commands
		MemoryPtr[AP] = sign? MemoryPtr[AP] - bias: MemoryPtr[AP] + bias;
		break;
	case 1:// '+' and '-' commands
		AP = sign? AP - bias: AP + bias;
		break;
	case 2://Console input cmd
		if (GetWordMode()){
			MemoryPtr[AP] = In();
		}
		else{
			MemoryPtr[AP] = In() & 0xFF;
		}
		break;
	case 3://console output cmd
		if (GetWordMode()){
			Out(MemoryPtr[AP]);
		}
		else{
			Out(MemoryPtr[AP] & 0xFF);
		}
		break;
	case 4://Jump If Zero
		if (GetWordMode()){
			IP = MemoryPtr[AP]? IP : (sign? IP - bias: IP + bias);
		}
		else{
			IP = (MemoryPtr[AP] & 0xFF)? IP : (sign? IP - bias: IP + bias);
		}
		break;
	case 5://Jump If not zero
		if (GetWordMode()){
			IP = MemoryPtr[AP]? (sign? IP - bias: IP + bias) : IP;
		}
		else{
			IP = (MemoryPtr[AP] & 0xFF)? (sign? IP - bias: IP + bias) : IP;
		}
		break;
	case 6://Set IP
		IP = bias;
		break;
	case 7://Set AP
		AP =  bias;
		break;
	}
	return status;
}

uint8_t ExecCode(Image &image, uint16_t *MemoryPtr){
	uint8_t status = 0;

	ADDRESS_TYPE IP = image.GetIpEntry();
	ADDRESS_TYPE AP = image.GetApEntry();

	size_t i = 0;
	do {
		i++;
		status = ExecCmd(image,MemoryPtr, IP, AP);
		if (status){
			return -1;
		}

		IP++;
	}while (IP < image.GetSection(0).GetMemoryBase().Word + image.GetSection(0).GetMemorySize().Word );
	cerr << "\r\nIstructions_retired:" << i << "\r\n";
	return status;
}

int main(int argc, char *argv[]) {
	int status = -1;
	int c = 0;
	char *filePath = NULL;
	while((c = getopt(argc, argv, "f:px")) != -1){
		switch(c)
		{
		case 'f':
			filePath = optarg;
			break;
		case 'p':
			SetProtectedMode(true);
		break;
		case 'x':
			SetWordMode(true);
		break;
		}
	}
	if (filePath == NULL){
		cout << "Fatal error: add input file"<< endl;
		return -1;
	}
	uint16_t Memory[65536];
	memset(&Memory,0,sizeof(Memory));
	std::fstream File(filePath, std::fstream::binary);
	if (!File.good()){
		return -1;
	}

	Image image(File, Memory);
	if (image.Error()){
		cerr << "Load BF buffer Error, Status =" << status << endl;
		return -1;
	}
	status = ExecCode(image, Memory);
	if (status){
		cerr << "Code Execution Error, Status =" << status << endl;
		return -1;
	}

	return 0;
}
<commit_msg>MOD: Show File.open error<commit_after>//============================================================================
// Name        : brainfuck_rpc_emulator.cpp
// Author      : Artem Kashkanov
// Version     :
// Copyright   :
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <iomanip>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <cstring>

#include "Console.h"

#include "Image.h"
#include <fstream>

#include <vector>

#include "bfutils.h"

using namespace std;

bool ProtectedModeEnabled = false;

void SetProtectedMode(bool mode){
     ProtectedModeEnabled = mode;
}

bool GetProtectedMode(void){
     return ProtectedModeEnabled;
}
//Set 16-bit word mode:
bool WordModeEnabled = false;

void SetWordMode(bool mode){
     WordModeEnabled = mode;
}

bool GetWordMode(void){
     return WordModeEnabled;
}

uint8_t ExecCmd(Image &image, uint16_t *MemoryPtr, uint16_t &IP, uint16_t &AP){
	uint8_t status = SUCCESS;
	uint16_t cmd = MemoryPtr[IP];
	uint16_t cmd_bin = ((cmd>>13) & 0x0007);
	bool sign = ((cmd >> 12)&0x01)? true: false;
	uint16_t bias = (cmd&0x0FFF);
	switch (cmd_bin){
	case 0:// '<' and '>' commands
		MemoryPtr[AP] = sign? MemoryPtr[AP] - bias: MemoryPtr[AP] + bias;
		break;
	case 1:// '+' and '-' commands
		AP = sign? AP - bias: AP + bias;
		break;
	case 2://Console input cmd
		if (GetWordMode()){
			MemoryPtr[AP] = In();
		}
		else{
			MemoryPtr[AP] = In() & 0xFF;
		}
		break;
	case 3://console output cmd
		if (GetWordMode()){
			Out(MemoryPtr[AP]);
		}
		else{
			Out(MemoryPtr[AP] & 0xFF);
		}
		break;
	case 4://Jump If Zero
		if (GetWordMode()){
			IP = MemoryPtr[AP]? IP : (sign? IP - bias: IP + bias);
		}
		else{
			IP = (MemoryPtr[AP] & 0xFF)? IP : (sign? IP - bias: IP + bias);
		}
		break;
	case 5://Jump If not zero
		if (GetWordMode()){
			IP = MemoryPtr[AP]? (sign? IP - bias: IP + bias) : IP;
		}
		else{
			IP = (MemoryPtr[AP] & 0xFF)? (sign? IP - bias: IP + bias) : IP;
		}
		break;
	case 6://Set IP
		IP = bias;
		break;
	case 7://Set AP
		AP =  bias;
		break;
	}
	return status;
}

uint8_t ExecCode(Image &image, uint16_t *MemoryPtr){
	uint8_t status = 0;

	ADDRESS_TYPE IP = image.GetIpEntry();
	ADDRESS_TYPE AP = image.GetApEntry();

	size_t i = 0;
	do {
		i++;
		status = ExecCmd(image,MemoryPtr, IP, AP);
		if (status){
			return -1;
		}

		IP++;
	}while (IP < image.GetSection(0).GetMemoryBase().Word + image.GetSection(0).GetMemorySize().Word );
	cerr << "\r\nIstructions_retired:" << i << "\r\n";
	return status;
}

int main(int argc, char *argv[]) {
	int status = -1;
	int c = 0;
	char *filePath = NULL;
	while((c = getopt(argc, argv, "f:px")) != -1){
		switch(c)
		{
		case 'f':
			filePath = optarg;
			break;
		case 'p':
			SetProtectedMode(true);
		break;
		case 'x':
			SetWordMode(true);
		break;
		}
	}
	if (filePath == NULL){
		cout << "Fatal error: add input file"<< endl;
		return -1;
	}
	uint16_t Memory[65536];
	memset(&Memory,0,sizeof(Memory));
	std::fstream File(filePath, std::fstream::in | std::fstream::binary);
	if (!File.good()){
		cerr << "Input file error, exiting"<<endl;
		return -1;
	}

	Image image(File, Memory);
	if (image.Error()){
		cerr << "Load BF buffer Error, Status =" << status << endl;
		return -1;
	}
	status = ExecCode(image, Memory);
	if (status){
		cerr << "Code Execution Error, Status =" << status << endl;
		return -1;
	}

	return 0;
}
<|endoftext|>