kis_low_memory_benchmark.cpp 7.82 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 *  Copyright (c) 2012 Dmitry Kazakov <dimula73@gmail.com>
 *
 *  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 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "kis_low_memory_benchmark.h"

21
#include <QTest>
22 23 24 25 26 27 28 29 30 31 32 33 34

#include "kis_benchmark_values.h"

#include <KoColor.h>
#include <KoColorSpace.h>
#include <KoColorSpaceRegistry.h>

#include <kis_image.h>
#include <kis_layer.h>
#include <kis_paint_layer.h>
#include "kis_paint_device.h"
#include "kis_painter.h"

Boudewijn Rempt's avatar
Boudewijn Rempt committed
35 36 37
#include <brushengine/kis_paint_information.h>
#include <brushengine/kis_paintop_registry.h>
#include <brushengine/kis_paintop_preset.h>
38 39 40 41 42

#include "tiles3/kis_tile_data_store.h"
#include "kis_surrogate_undo_adapter.h"
#include "kis_image_config.h"
#define LOAD_PRESET_OR_RETURN(preset, fileName)                         \
43 44
    if(!preset->load()) { dbgKrita << "Preset" << fileName << "was NOT loaded properly. Done."; return; } \
    else dbgKrita << "Loaded preset:" << fileName
45

46 47
#define HUGE_IMAGE_SIZE 8000

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
/**
 * This benchmark runs a series of huge strokes on a canvas with a
 * particular configuration of the swapper/pooler and history
 * management. After the test is done you can visualize the results
 * with the GNU Octave. Please use kis_low_memory_show_report.m file
 * for that.
 */
void KisLowMemoryBenchmark::benchmarkWideArea(const QString presetFileName,
                                              const QRectF &rect, qreal vstep,
                                              int numCycles,
                                              bool createTransaction,
                                              int hardLimitMiB,
                                              int softLimitMiB,
                                              int poolLimitMiB,
                                              int index)
{
    KisPaintOpPresetSP preset = new KisPaintOpPreset(QString(FILES_DATA_DIR) + QDir::separator() + presetFileName);
    LOAD_PRESET_OR_RETURN(preset, presetFileName);


    /**
     * Initialize image and painter
     */
    const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8();
72
    KisImageSP image = new KisImage(0, HUGE_IMAGE_SIZE, HUGE_IMAGE_SIZE, colorSpace, "stroke sample image");
73
    KisLayerSP layer = new KisPaintLayer(image, "temporary for stroke sample", OPACITY_OPAQUE_U8, colorSpace);
74 75 76 77 78
    KisLayerSP layerExtra = new KisPaintLayer(image, "temporary for threading", OPACITY_OPAQUE_U8, colorSpace);

    image->addNode(layer, image->root());
    image->addNode(layerExtra, image->root());

79 80 81
    KisPainter *painter = new KisPainter(layer->paintDevice());

    painter->setPaintColor(KoColor(Qt::black, colorSpace));
82
    painter->setPaintOpPreset(preset, layer, image);
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

    /**
     * A simple adapter that will store all the transactions for us
     */
    KisSurrogateUndoAdapter undoAdapter;

    /**
     * Reset configuration to the desired settings
     */
    KisImageConfig config;
    qreal oldHardLimit = config.memoryHardLimitPercent();
    qreal oldSoftLimit = config.memorySoftLimitPercent();
    qreal oldPoolLimit = config.memoryPoolLimitPercent();
    const qreal _MiB = 100.0 / KisImageConfig::totalRAM();

    config.setMemoryHardLimitPercent(hardLimitMiB * _MiB);
    config.setMemorySoftLimitPercent(softLimitMiB * _MiB);
    config.setMemoryPoolLimitPercent(poolLimitMiB * _MiB);

    KisTileDataStore::instance()->testingRereadConfig();

    /**
     * Create an empty the log file
     */
    QString fileName;
    fileName = QString("log_%1_%2_%3_%4_%5.txt")
        .arg(createTransaction)
        .arg(hardLimitMiB)
        .arg(softLimitMiB)
        .arg(poolLimitMiB)
        .arg(index);

    QFile logFile(fileName);
    logFile.open(QFile::WriteOnly | QFile::Truncate);
    QTextStream logStream(&logFile);
    logStream.setFieldWidth(10);
    logStream.setFieldAlignment(QTextStream::AlignRight);

    /**
     * Start painting on the image
     */

    QTime cycleTime;
    QTime lineTime;
    cycleTime.start();
    lineTime.start();

    qreal rectBottom = rect.y() + rect.height();

    for (int i = 0; i < numCycles; i++) {
        cycleTime.restart();

        QLineF line(rect.topLeft(), rect.topLeft() + QPointF(rect.width(), 0));
        if (createTransaction) {
137
            painter->beginTransaction();
138 139
        }

140 141
        KisDistanceInformation currentDistance;

142 143 144 145 146
        while(line.y1() < rectBottom) {
            lineTime.restart();

            KisPaintInformation pi1(line.p1(), 0.0);
            KisPaintInformation pi2(line.p2(), 1.0);
147
            painter->paintLine(pi1, pi2, &currentDistance);
148
            painter->device()->setDirty(painter->takeDirtyRegion());
149 150 151 152 153 154 155 156

            logStream << "L 1" << i << lineTime.elapsed()
                      << KisTileDataStore::instance()->numTilesInMemory() * 16
                      << KisTileDataStore::instance()->numTiles() * 16
                      << createTransaction << endl;

            line.translate(0, vstep);
        }
157 158 159

        painter->device()->setDirty(painter->takeDirtyRegion());

160 161 162 163
        if (createTransaction) {
            painter->endTransaction(&undoAdapter);
        }

164 165
        // comment/uncomment to emulate user waiting after the stroke
        QTest::qSleep(1000);
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218

        logStream << "C 2" << i << cycleTime.elapsed()
                  << KisTileDataStore::instance()->numTilesInMemory() * 16
                  << KisTileDataStore::instance()->numTiles() * 16
                  << createTransaction
                  << config.memoryHardLimitPercent() / _MiB
                  << config.memorySoftLimitPercent() / _MiB
                  << config.memoryPoolLimitPercent() / _MiB  << endl;
    }

    config.setMemoryHardLimitPercent(oldHardLimit * _MiB);
    config.setMemorySoftLimitPercent(oldSoftLimit * _MiB);
    config.setMemoryPoolLimitPercent(oldPoolLimit * _MiB);

    delete painter;
}

void KisLowMemoryBenchmark::unlimitedMemoryNoHistoryNoPool()
{
    QString presetFileName = "autobrush_300px.kpp";
    // one cycle takes about 48 MiB of memory (total 960 MiB)
    QRectF rect(150,150,4000,4000);
    qreal step = 250;
    int numCycles = 20;

    benchmarkWideArea(presetFileName, rect, step, numCycles, false,
                      3000, 3000, 0, 0);
}

void KisLowMemoryBenchmark::unlimitedMemoryHistoryNoPool()
{
    QString presetFileName = "autobrush_300px.kpp";
    // one cycle takes about 48 MiB of memory (total 960 MiB)
    QRectF rect(150,150,4000,4000);
    qreal step = 250;
    int numCycles = 20;

    benchmarkWideArea(presetFileName, rect, step, numCycles, true,
                      3000, 3000, 0, 0);
}

void KisLowMemoryBenchmark::unlimitedMemoryHistoryPool50()
{
    QString presetFileName = "autobrush_300px.kpp";
    // one cycle takes about 48 MiB of memory (total 960 MiB)
    QRectF rect(150,150,4000,4000);
    qreal step = 250;
    int numCycles = 20;

    benchmarkWideArea(presetFileName, rect, step, numCycles, true,
                      3000, 3000, 50, 0);
}

219 220 221 222 223 224 225 226 227 228 229 230
void KisLowMemoryBenchmark::memory2000History100Pool500HugeBrush()
{
    QString presetFileName = "BIG_TESTING.kpp";
    // one cycle takes about 316 MiB of memory (total 3+ GiB)
    QRectF rect(150,150,7850,7850);
    qreal step = 250;
    int numCycles = 10;

    benchmarkWideArea(presetFileName, rect, step, numCycles, true,
                      2000, 600, 500, 0);
}

231
QTEST_MAIN(KisLowMemoryBenchmark)