<commit_before>#include <fstream>
#include <iterator>
#include <sstream>
#include <string>

#include "tuning_runner.h"
#include "searcher/annealing_searcher.h"
#include "searcher/full_searcher.h"
#include "searcher/pso_searcher.h"
#include "searcher/random_searcher.h"
#include "utility/ktt_utility.h"
#include "utility/timer.h"

namespace ktt
{

TuningRunner::TuningRunner(ArgumentManager* argumentManager, KernelManager* kernelManager, Logger* logger, ComputeApiDriver* computeApiDriver) :
    argumentManager(argumentManager),
    kernelManager(kernelManager),
    logger(logger),
    computeApiDriver(computeApiDriver),
    resultValidator(argumentManager, kernelManager, logger, computeApiDriver),
    manipulatorInterfaceImplementation(std::make_unique<ManipulatorInterfaceImplementation>(computeApiDriver))
{}

std::pair<std::vector<TuningResult>, std::vector<TuningResult>> TuningRunner::tuneKernel(const size_t id)
{
    if (id >= kernelManager->getKernelCount())
    {
        throw std::runtime_error(std::string("Invalid kernel id: ") + std::to_string(id));
    }

    std::vector<TuningResult> results;
    std::vector<TuningResult> invalidResults;

    const Kernel* kernel = kernelManager->getKernel(id);
    resultValidator.computeReferenceResult(kernel);

    std::unique_ptr<Searcher> searcher = getSearcher(kernel->getSearchMethod(), kernel->getSearchArguments(),
        kernelManager->getKernelConfigurations(id, computeApiDriver->getCurrentDeviceInfo()), kernel->getParameters());
    size_t configurationsCount = searcher->getConfigurationsCount();

    for (size_t i = 0; i < configurationsCount; i++)
    {
        KernelConfiguration currentConfiguration = searcher->getNextConfiguration();
        KernelRunResult result;
        uint64_t manipulatorDuration = 0;

        try
        {
            auto resultPair = runKernel(kernel, currentConfiguration, i, configurationsCount);
            result = resultPair.first;
            manipulatorDuration = resultPair.second;
        }
        catch (const std::runtime_error& error)
        {
            logger->log(std::string("Kernel run failed, reason: ") + error.what() + "\n");
            invalidResults.push_back(TuningResult(kernel->getName(), currentConfiguration, std::string("Failed kernel run: ") + error.what()));
        }

        searcher->calculateNextConfiguration(static_cast<double>(result.getDuration() + manipulatorDuration));
        if (validateResult(kernel, result, manipulatorDuration, currentConfiguration))
        {
            results.emplace_back(TuningResult(kernel->getName(), result.getDuration(), manipulatorDuration, currentConfiguration));
        }
        else
        {
            invalidResults.push_back(TuningResult(kernel->getName(), currentConfiguration, "Results differ"));
        }

        computeApiDriver->clearBuffers(ArgumentMemoryType::ReadWrite);
        computeApiDriver->clearBuffers(ArgumentMemoryType::WriteOnly);

        auto manipulatorPointer = manipulatorMap.find(kernel->getId());
        if (manipulatorPointer != manipulatorMap.end())
        {
            computeApiDriver->clearBuffers(ArgumentMemoryType::ReadOnly);
        }
    }

    computeApiDriver->clearBuffers();
    resultValidator.clearReferenceResults();
    return std::make_pair(results, invalidResults);
}

void TuningRunner::setValidationMethod(const ValidationMethod& validationMethod, const double toleranceThreshold)
{
    resultValidator.setValidationMethod(validationMethod);
    resultValidator.setToleranceThreshold(toleranceThreshold);
}

void TuningRunner::setValidationRange(const size_t argumentId, const size_t validationRange)
{
    resultValidator.setValidationRange(argumentId, validationRange);
}

void TuningRunner::setReferenceKernel(const size_t kernelId, const size_t referenceKernelId,
    const std::vector<ParameterValue>& referenceKernelConfiguration, const std::vector<size_t>& resultArgumentIds)
{
    resultValidator.setReferenceKernel(kernelId, referenceKernelId, referenceKernelConfiguration, resultArgumentIds);
}

void TuningRunner::setReferenceClass(const size_t kernelId, std::unique_ptr<ReferenceClass> referenceClass,
    const std::vector<size_t>& resultArgumentIds)
{
    resultValidator.setReferenceClass(kernelId, std::move(referenceClass), resultArgumentIds);
}

void TuningRunner::setTuningManipulator(const size_t kernelId, std::unique_ptr<TuningManipulator> tuningManipulator)
{
    if (manipulatorMap.find(kernelId) != manipulatorMap.end())
    {
        manipulatorMap.erase(kernelId);
    }
    manipulatorMap.insert(std::make_pair(kernelId, std::move(tuningManipulator)));
}

void TuningRunner::enableArgumentPrinting(const size_t argumentId, const std::string& filePath, const ArgumentPrintCondition& argumentPrintCondition)
{
    resultValidator.enableArgumentPrinting(argumentId, filePath, argumentPrintCondition);
}

std::pair<KernelRunResult, uint64_t> TuningRunner::runKernel(const Kernel* kernel, const KernelConfiguration& currentConfiguration,
    const size_t currentConfigurationIndex, const size_t configurationsCount)
{
    KernelRunResult result;
    size_t kernelId = kernel->getId();
    std::string kernelName = kernel->getName();
    std::string source = kernelManager->getKernelSourceWithDefines(kernelId, currentConfiguration);
    std::stringstream stream;

    auto manipulatorPointer = manipulatorMap.find(kernelId);
    if (manipulatorPointer != manipulatorMap.end())
    {
        stream << "Launching kernel <" << kernelName << "> (manipulator detected) with configuration (" << currentConfigurationIndex + 1 << " / "
            << configurationsCount << "): " << currentConfiguration;
        logger->log(stream.str());
        auto kernelDataVector = getKernelDataVector(kernelId, KernelRuntimeData(kernelName, source, currentConfiguration.getGlobalSize(),
            currentConfiguration.getLocalSize(), kernel->getArgumentIndices()), manipulatorPointer->second->getUtilizedKernelIds(),
            currentConfiguration);
        return runKernelWithManipulator(manipulatorPointer->second.get(), kernelDataVector, currentConfiguration);
    }

    stream << "Launching kernel <" << kernelName << "> with configuration (" << currentConfigurationIndex + 1  << " / " << configurationsCount
        << "): " << currentConfiguration;
    logger->log(stream.str());
    result = computeApiDriver->runKernel(source, kernel->getName(), convertDimensionVector(currentConfiguration.getGlobalSize()),
        convertDimensionVector(currentConfiguration.getLocalSize()), getKernelArgumentPointers(kernelId));
    return std::make_pair(result, 0);
}

std::pair<KernelRunResult, uint64_t> TuningRunner::runKernelWithManipulator(TuningManipulator* manipulator,
    const std::vector<std::pair<size_t, KernelRuntimeData>>& kernelDataVector, const KernelConfiguration& currentConfiguration)
{
    manipulator->manipulatorInterface = manipulatorInterfaceImplementation.get();
    std::vector<KernelArgument> kernelArguments;
    for (const auto& kernelData : kernelDataVector)
    {
        manipulatorInterfaceImplementation->addKernel(kernelData.first, kernelData.second);
        auto currentArguments = getKernelArguments(kernelData.first);
        for (const auto& argument : currentArguments)
        {
            if (!elementExists(argument, kernelArguments))
            {
                kernelArguments.push_back(argument);
            }
        }
    }
    manipulatorInterfaceImplementation->setConfiguration(currentConfiguration);
    manipulatorInterfaceImplementation->setKernelArguments(kernelArguments);
    manipulatorInterfaceImplementation->uploadBuffers();

    Timer timer;
    timer.start();
    manipulator->launchComputation(kernelDataVector.at(0).first);
    timer.stop();

    KernelRunResult result = manipulatorInterfaceImplementation->getCurrentResult();
    size_t manipulatorDuration = timer.getElapsedTime();
    manipulatorDuration -= result.getOverhead();

    manipulatorInterfaceImplementation->clearData();
    manipulator->manipulatorInterface = nullptr;<commit_msg>Fixed possible resource leak when using tuning manipulator<commit_after>#include <fstream>
#include <iterator>
#include <sstream>
#include <string>

#include "tuning_runner.h"
#include "searcher/annealing_searcher.h"
#include "searcher/full_searcher.h"
#include "searcher/pso_searcher.h"
#include "searcher/random_searcher.h"
#include "utility/ktt_utility.h"
#include "utility/timer.h"

namespace ktt
{

TuningRunner::TuningRunner(ArgumentManager* argumentManager, KernelManager* kernelManager, Logger* logger, ComputeApiDriver* computeApiDriver) :
    argumentManager(argumentManager),
    kernelManager(kernelManager),
    logger(logger),
    computeApiDriver(computeApiDriver),
    resultValidator(argumentManager, kernelManager, logger, computeApiDriver),
    manipulatorInterfaceImplementation(std::make_unique<ManipulatorInterfaceImplementation>(computeApiDriver))
{}

std::pair<std::vector<TuningResult>, std::vector<TuningResult>> TuningRunner::tuneKernel(const size_t id)
{
    if (id >= kernelManager->getKernelCount())
    {
        throw std::runtime_error(std::string("Invalid kernel id: ") + std::to_string(id));
    }

    std::vector<TuningResult> results;
    std::vector<TuningResult> invalidResults;

    const Kernel* kernel = kernelManager->getKernel(id);
    resultValidator.computeReferenceResult(kernel);

    std::unique_ptr<Searcher> searcher = getSearcher(kernel->getSearchMethod(), kernel->getSearchArguments(),
        kernelManager->getKernelConfigurations(id, computeApiDriver->getCurrentDeviceInfo()), kernel->getParameters());
    size_t configurationsCount = searcher->getConfigurationsCount();

    for (size_t i = 0; i < configurationsCount; i++)
    {
        KernelConfiguration currentConfiguration = searcher->getNextConfiguration();
        KernelRunResult result;
        uint64_t manipulatorDuration = 0;

        try
        {
            auto resultPair = runKernel(kernel, currentConfiguration, i, configurationsCount);
            result = resultPair.first;
            manipulatorDuration = resultPair.second;
        }
        catch (const std::runtime_error& error)
        {
            logger->log(std::string("Kernel run failed, reason: ") + error.what() + "\n");
            invalidResults.push_back(TuningResult(kernel->getName(), currentConfiguration, std::string("Failed kernel run: ") + error.what()));
        }

        searcher->calculateNextConfiguration(static_cast<double>(result.getDuration() + manipulatorDuration));
        if (validateResult(kernel, result, manipulatorDuration, currentConfiguration))
        {
            results.emplace_back(TuningResult(kernel->getName(), result.getDuration(), manipulatorDuration, currentConfiguration));
        }
        else
        {
            invalidResults.push_back(TuningResult(kernel->getName(), currentConfiguration, "Results differ"));
        }

        computeApiDriver->clearBuffers(ArgumentMemoryType::ReadWrite);
        computeApiDriver->clearBuffers(ArgumentMemoryType::WriteOnly);

        auto manipulatorPointer = manipulatorMap.find(kernel->getId());
        if (manipulatorPointer != manipulatorMap.end())
        {
            computeApiDriver->clearBuffers(ArgumentMemoryType::ReadOnly);
        }
    }

    computeApiDriver->clearBuffers();
    resultValidator.clearReferenceResults();
    return std::make_pair(results, invalidResults);
}

void TuningRunner::setValidationMethod(const ValidationMethod& validationMethod, const double toleranceThreshold)
{
    resultValidator.setValidationMethod(validationMethod);
    resultValidator.setToleranceThreshold(toleranceThreshold);
}

void TuningRunner::setValidationRange(const size_t argumentId, const size_t validationRange)
{
    resultValidator.setValidationRange(argumentId, validationRange);
}

void TuningRunner::setReferenceKernel(const size_t kernelId, const size_t referenceKernelId,
    const std::vector<ParameterValue>& referenceKernelConfiguration, const std::vector<size_t>& resultArgumentIds)
{
    resultValidator.setReferenceKernel(kernelId, referenceKernelId, referenceKernelConfiguration, resultArgumentIds);
}

void TuningRunner::setReferenceClass(const size_t kernelId, std::unique_ptr<ReferenceClass> referenceClass,
    const std::vector<size_t>& resultArgumentIds)
{
    resultValidator.setReferenceClass(kernelId, std::move(referenceClass), resultArgumentIds);
}

void TuningRunner::setTuningManipulator(const size_t kernelId, std::unique_ptr<TuningManipulator> tuningManipulator)
{
    if (manipulatorMap.find(kernelId) != manipulatorMap.end())
    {
        manipulatorMap.erase(kernelId);
    }
    manipulatorMap.insert(std::make_pair(kernelId, std::move(tuningManipulator)));
}

void TuningRunner::enableArgumentPrinting(const size_t argumentId, const std::string& filePath, const ArgumentPrintCondition& argumentPrintCondition)
{
    resultValidator.enableArgumentPrinting(argumentId, filePath, argumentPrintCondition);
}

std::pair<KernelRunResult, uint64_t> TuningRunner::runKernel(const Kernel* kernel, const KernelConfiguration& currentConfiguration,
    const size_t currentConfigurationIndex, const size_t configurationsCount)
{
    KernelRunResult result;
    size_t kernelId = kernel->getId();
    std::string kernelName = kernel->getName();
    std::string source = kernelManager->getKernelSourceWithDefines(kernelId, currentConfiguration);
    std::stringstream stream;

    auto manipulatorPointer = manipulatorMap.find(kernelId);
    if (manipulatorPointer != manipulatorMap.end())
    {
        stream << "Launching kernel <" << kernelName << "> (manipulator detected) with configuration (" << currentConfigurationIndex + 1 << " / "
            << configurationsCount << "): " << currentConfiguration;
        logger->log(stream.str());
        auto kernelDataVector = getKernelDataVector(kernelId, KernelRuntimeData(kernelName, source, currentConfiguration.getGlobalSize(),
            currentConfiguration.getLocalSize(), kernel->getArgumentIndices()), manipulatorPointer->second->getUtilizedKernelIds(),
            currentConfiguration);
        return runKernelWithManipulator(manipulatorPointer->second.get(), kernelDataVector, currentConfiguration);
    }

    stream << "Launching kernel <" << kernelName << "> with configuration (" << currentConfigurationIndex + 1  << " / " << configurationsCount
        << "): " << currentConfiguration;
    logger->log(stream.str());
    result = computeApiDriver->runKernel(source, kernel->getName(), convertDimensionVector(currentConfiguration.getGlobalSize()),
        convertDimensionVector(currentConfiguration.getLocalSize()), getKernelArgumentPointers(kernelId));
    return std::make_pair(result, 0);
}

std::pair<KernelRunResult, uint64_t> TuningRunner::runKernelWithManipulator(TuningManipulator* manipulator,
    const std::vector<std::pair<size_t, KernelRuntimeData>>& kernelDataVector, const KernelConfiguration& currentConfiguration)
{
    manipulator->manipulatorInterface = manipulatorInterfaceImplementation.get();
    std::vector<KernelArgument> kernelArguments;
    for (const auto& kernelData : kernelDataVector)
    {
        manipulatorInterfaceImplementation->addKernel(kernelData.first, kernelData.second);
        auto currentArguments = getKernelArguments(kernelData.first);
        for (const auto& argument : currentArguments)
        {
            if (!elementExists(argument, kernelArguments))
            {
                kernelArguments.push_back(argument);
            }
        }
    }
    manipulatorInterfaceImplementation->setConfiguration(currentConfiguration);
    manipulatorInterfaceImplementation->setKernelArguments(kernelArguments);
    manipulatorInterfaceImplementation->uploadBuffers();

    Timer timer;
    try
    {
        timer.start();
        manipulator->launchComputation(kernelDataVector.at(0).first);
        timer.stop();
    }
    catch (const std::runtime_error&)
    {
        manipulatorInterfaceImplementation->clearData();
        manipulator->manipulatorInterface = nullptr;
        throw;
    }

    KernelRunResult result = manipulatorInterfaceImplementation->getCurrentResult();
    size_t manipulatorDuration = timer.getElapsedTime();
    manipulatorDuration -= result.getOverhead();

    manipulatorInterfaceImplementation->clearData();
    manipulator->manipulatorInterface = nullptr;
{'fraction_non_alphanumeric': 0.10705581281988788, 'fraction_numerical': 0.0014623446258835, 'mean_word_length': 5.014290949065591, 'pattern_counts': {'":': 0, '<': 117, '<?xml version=': 0, '>': 133, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1352629', 'n_tokens_mistral': 4250, 'n_tokens_neox': 4247, 'n_words': 716}