<commit_before>/* @(#)dtkDistributedResourceManagerOar.cpp ---
 *
 * Author: Nicolas Niclausse
 * Copyright (C) 2014 - Nicolas Niclausse, Inria.
 * Created: 2014/04/25 08:18:49
 */

/* Commentary:
 *
 */

/* Change log:
 *
 */

#include "dtkDistributedResourceManagerOar.h"

#include <dtkLog>

// /////////////////////////////////////////////////////////////////
// dtkDistributedResourceManagerOar implementation
// /////////////////////////////////////////////////////////////////

QString  dtkDistributedResourceManagerOar::submit(QString input)
{
    QString oarsub = "oarsub ";

    QJsonDocument jsonDoc = QJsonDocument::fromJson(input.toUtf8());

    if (jsonDoc.isNull() || !jsonDoc.isObject()) {
        dtkWarn() << "Error while parsing JSON document: not a json object" << input;
        return QString("ERROR");
    }
    QVariantMap json = jsonDoc.object().toVariantMap();

    QVariantMap jprops = json["properties"].toMap();
    QString properties ;
    if (jprops.contains("cpu_model")) {
        properties +=  " -p \"cputype='"+jprops["cpu_model"].toString()+"'\"";
    } else if (jprops.contains("cluster")) {
        properties +=  " -p \"cluster='"+jprops["cluster"].toString()+"'\"";
    }
    // TODO:handle other properties

    QVariantMap res = json["resources"].toMap();

    if (res["nodes"].toInt() == 0) {
        // no nodes, only cores;
        oarsub += " -l /core="+res["cores"].toString();
    } else if (res["cores"].toInt() == 0) {
        // no cores, only nodes;
        oarsub += " -l /nodes="+res["nodes"].toString();
    } else {
        oarsub += " -l /nodes="+res["nodes"].toString()+"/core="+res["cores"].toString();
    }

    // walltime, syntax=HH:MM:SS
    if (json.contains("walltime")) {
        oarsub += ",walltime="+json["walltime"].toString();
    }

    // script
    if (json.contains("script")) {
        oarsub += " "+json["script"].toString();
    } else if (json.contains("application")) {

        QString scriptName = qApp->applicationDirPath() + "/dtkDistributedServerScript.sh";
        QFile script(scriptName);

        if (!script.open(QFile::WriteOnly|QFile::Truncate)) {
            dtkWarn() << "unable to open script for writing";
        } else {
            script.setPermissions(QFile::ExeOwner|QFile::ReadOwner|QFile::WriteOwner);
            QTextStream out(&script);
            QString app_path = json["application"].toString();
            out << "#!/bin/bash\n";
            if (QFileInfo(app_path).isAbsolute()) {
                out << json["application"].toString();
            } else {
                out <<  qApp->applicationDirPath()
                    + "/"
                    + app_path;
            }
        }

        script.close();

        oarsub += " " + scriptName;

    } else {
        dtkError() << "no script and no application";
        return QString("ERROR");
    }

    // queue
    if (json.contains("queue")) {
        oarsub += " -q "+json["queue"].toString();
    }
    // options
    if (json.contains("options")) {
        oarsub += " "+json["options"].toString();
    }

    dtkDebug() << oarsub;
    QProcess stat; stat.start(oarsub);

    if (!stat.waitForStarted()) {
        dtkError() << "Unable to launch oarsub command";
        return QString("error");
    }

    if (!stat.waitForFinished()) {
        dtkError() << "Unable to completed oarsub command";
        return QString("error");
    }
    if (stat.exitCode() > 0) {
        QString error = stat.readAllStandardError();
        dtkError() << "Error running oarsub :" << error;
        return QString("error");
    } else {
        QString oarsubout = stat.readAll();

        QRegExp rx("OAR_JOB_ID=(\\d+)");
        int pos = rx.indexIn(oarsubout);
        QStringList jobid = rx.capturedTexts();

        Q_UNUSED(pos);

        dtkDebug() << jobid.at(1);
        return jobid.at(1);
    }
}

QString dtkDistributedResourceManagerOar::deljob(QString jobid)
{

    QString oardel = "oardel " + jobid;
    QProcess stat; stat.start(oardel);

    if (!stat.waitForStarted()) {
        dtkError() << "Unable to launch oardel command";
        return QString("ERROR");
    }

    if (!stat.waitForFinished()) {
        dtkError() << "Unable to complete oardel command";
        return QString("ERROR");
    }
    if (stat.exitCode() > 0) {
        QString error = stat.readAllStandardError();
        dtkError() << "Error running oardel :" << error;
        return QString("ERROR");
    } else {
        QString msg = stat.readAll();
        dtkDebug() << msg;
        return QString("OK");
    }
}

QByteArray dtkDistributedResourceManagerOar::status(void)
{
    QProcess stat;
    QString data;
    QVariantMap json;
    QVariantMap result;

    // get the jobs
    stat.start("oarstat -fJ");

    if (!stat.waitForStarted()) {
        dtkError() << "Unable to launch oarstat command";
        return QByteArray();
    }

    if (!stat.waitForFinished()) {
        dtkError() << "Unable to completed oarstat command";
        return QByteArray();
    }

    data = stat.readAll();

    QJsonDocument jsonDoc = QJsonDocument::fromJson(data.toUtf8());

    if (jsonDoc.isNull() || !jsonDoc.isObject()) {
        dtkError() << "Error while parsing JSON document (OAR) : not a json object" << data;
        return QByteArray();
    }
    json = jsonDoc.object().toVariantMap();

    stat.close();

    QVariantList jobs;
    QHash<QString, QString> activecores; //key is core id, value is jobid

    foreach(QVariant qv, json) {
        QVariantMap job = qv.toMap();
        QVariantMap dtkjob;
        QString id = job["Job_Id"].toString();
        QString user = job["job_user"].toString();
        QString queue = job["queue"].toString();
        QString qtime = job["submissionTime"].toString();
        QString stime = job["scheduledStart"].toString();
        QString walltime ;
        QString state =job["state"].toString();
        if (state == "Running")
            state = "running";
        else if ((state == "Waiting") && (job["reservation"].toString() == "scheduled"))
            state = "scheduled";
        else if (state == "Waiting")
            state = "queued";
        else if (state == "Suspended")
            state = "suspended";
        else if (state == "Hold")
            state = "blocked";
        else if (state == "Finishing")
            state = "exiting";
        else
            state = "unknown";

        foreach(QVariant coreid, job["assigned_resources"].toList()) {
            activecores[coreid.toString()] = id;
        }

        QRegExp rx("/host=(\\d+|ALL|BEST)(?:/core=)?(\\d+)?.*(?:walltime=)?(\\d+:\\d+:\\d+)");

        int pos = rx.indexIn(job["wanted_resources"].toString());

        Q_UNUSED(pos);

        QStringList resources_list = rx.capturedTexts();
        qlonglong nodes = resources_list.at(1).toInt();
        qlonglong cores = resources_list.at(2).toInt();
        if (resources_list.count() > 3) {
            walltime = resources_list.at(3);
        } else {
            walltime = job["walltime"].toString(); //TODO: convert it to HH:MM:SS
            dtkDebug() << "can't find walltime from wanted resources! " << walltime;
        }

        QVariantMap jresources;

        jresources.insert("nodes",nodes);
        jresources.insert("cores",cores);

        dtkjob.insert("id", id);
        dtkjob.insert("username", user);
        dtkjob.insert("queue", queue);
        dtkjob.insert("queue_time", qtime);
        dtkjob.insert("start_time", stime);
        dtkjob.insert("walltime", walltime);
        dtkjob.insert("resources", jresources);
        dtkjob.insert("state", state);
        jobs << dtkjob;
        result.insert("jobs", jobs);
    }

    // Now get the nodes

    stat.start("oarnodes -J --sql \"host!=''\"");

    if (!stat.waitForStarted()) {
        dtkError() << "Unable to launch oarnodes command";
        return QByteArray();
    }

    if (!stat.waitForFinished()) {
        dtkError() << "Unable to completed oarnodes command";
        return QByteArray();
    }

    data = stat.readAll();

    jsonDoc = QJsonDocument::fromJson(data.toUtf8());

    if (jsonDoc.isNull() || !jsonDoc.isObject()) {
        dtkError() << "Error while parsing JSON document (OAR) : not a JSON object" << data;
        return QByteArray();
    }
    json = jsonDoc.object().toVariantMap();

    stat.close();

    QVariantMap nodes;
    foreach(QVariant qv, json) {
        QVariantMap jcore = qv.toMap();
        if (nodes.contains(jcore["host"].toString())) {
            QVariantMap core;
            QVariantMap node = nodes[jcore["host"].toString()].toMap();
            QVariantList cores = node["cores"].toList();
            QVariantList cpuids = node["cpuids"].toList();

            core.insert("id",jcore["resource_id"].toString());
            if (!activecores[core["id"].toString()].isEmpty()) {
                core.insert("job",activecores[core["id"].toString()]);
                int current_busy_cores = node["cores_busy"].toInt();
                node.insert("cores_busy", current_busy_cores+1);
            }
            qlonglong cpuid =  jcore["cpu"].toLongLong();
            if (!cpuids.contains(cpuid)) {
                cpuids <<  cpuid;
            }
            cores.append(core);
            node["cores"] = cores;
            node["cpuids"] = cpuids;
            nodes[jcore["host"].toString()] = node;
        } else { // new node
            QVariantList cores;
            QVariantList cpuids;
            QVariantList props;
            QVariantMap prop;
            QVariantMap core;
            QVariantMap node;
            if (jcore["cputype"].toString().contains("opteron")) {
                prop.insert("cpu_model","opteron");
                prop.insert("cpu_arch","x86_64");
            } else if (jcore["cputype"].toString().contains("xeon")) {
                prop.insert("cpu_model","xeon");
                prop.insert("cpu_arch","x86_64");
            }
            node.insert("name",jcore["host"]);
            QString state;
            if (jcore["state"].toString() == "Absent")
                if (jcore["available_upto"].toLongLong() > 0)
                    state = "standby";
                else
                    state = "absent";
            else if (jcore["state"].toString() == "Dead")
                state = "down";
            else if (jcore["state"].toString() == "Suspected")
                state = "absent";
            else if (jcore["state"].toString() == "Alive") {
                if (jcore["jobs"].toString().isEmpty())
                    state = "free";
                else
                    state = "busy";
            }
            node.insert("state", state);
            cpuids << jcore["cpu"].toLongLong();
            node.insert("cpuids",cpuids);
            core.insert("id",jcore["resource_id"]);
            if (!activecores[core["id"].toString()].isEmpty()) {
                core.insert("job",activecores[core["id"].toString()]);
                node.insert("cores_busy",1);
            } else {
                node.insert("cores_busy",0);
            }
            cores << core;
            props << prop;
            node.insert("cores",cores);
            node.insert("properties",props);
            nodes.insert(jcore["host"].toString(), node);
        }
    }

    QVariantList realnodes;
    // now we can compute the number of cpus per node
    foreach(QVariant qv, nodes) {
        QVariantMap map = qv.toMap();
        qlonglong cpus  = map["cpuids"].toList().count();
        qlonglong cores = map["cores"].toList().count();
        map.insert("cpus", cpus);
        map.remove("cpuids");
        realnodes << map;
    }
    result.insert("nodes", realnodes);

    return QJsonDocument(QJsonObject::fromVariantMap(result)).toJson();
}
<commit_msg>OAr: fix computation of core/nodes<commit_after>/* @(#)dtkDistributedResourceManagerOar.cpp ---
 *
 * Author: Nicolas Niclausse
 * Copyright (C) 2014 - Nicolas Niclausse, Inria.
 * Created: 2014/04/25 08:18:49
 */

/* Commentary:
 *
 */

/* Change log:
 *
 */

#include "dtkDistributedResourceManagerOar.h"

#include <dtkLog>

// /////////////////////////////////////////////////////////////////
// dtkDistributedResourceManagerOar implementation
// /////////////////////////////////////////////////////////////////

QString  dtkDistributedResourceManagerOar::submit(QString input)
{
    QString oarsub = "oarsub ";

    QJsonDocument jsonDoc = QJsonDocument::fromJson(input.toUtf8());

    if (jsonDoc.isNull() || !jsonDoc.isObject()) {
        dtkWarn() << "Error while parsing JSON document: not a json object" << input;
        return QString("ERROR");
    }
    QVariantMap json = jsonDoc.object().toVariantMap();

    QVariantMap jprops = json["properties"].toMap();
    QString properties ;
    if (jprops.contains("cpu_model")) {
        properties +=  " -p \"cputype='"+jprops["cpu_model"].toString()+"'\"";
    } else if (jprops.contains("cluster")) {
        properties +=  " -p \"cluster='"+jprops["cluster"].toString()+"'\"";
    }
    // TODO:handle other properties

    QVariantMap res = json["resources"].toMap();

    if (res["nodes"].toInt() == 0) {
        // no nodes, only cores;
        oarsub += " -l /core="+res["cores"].toString();
    } else if (res["cores"].toInt() == 0) {
        // no cores, only nodes;
        oarsub += " -l /nodes="+res["nodes"].toString();
    } else {
        oarsub += " -l /nodes="+res["nodes"].toString()+"/core="+res["cores"].toString();
    }

    // walltime, syntax=HH:MM:SS
    if (json.contains("walltime")) {
        oarsub += ",walltime="+json["walltime"].toString();
    }

    // script
    if (json.contains("script")) {
        oarsub += " "+json["script"].toString();
    } else if (json.contains("application")) {

        QString scriptName = qApp->applicationDirPath() + "/dtkDistributedServerScript.sh";
        QFile script(scriptName);

        if (!script.open(QFile::WriteOnly|QFile::Truncate)) {
            dtkWarn() << "unable to open script for writing";
        } else {
            script.setPermissions(QFile::ExeOwner|QFile::ReadOwner|QFile::WriteOwner);
            QTextStream out(&script);
            QString app_path = json["application"].toString();
            out << "#!/bin/bash\n";
            if (QFileInfo(app_path).isAbsolute()) {
                out << json["application"].toString();
            } else {
                out <<  qApp->applicationDirPath()
                    + "/"
                    + app_path;
            }
        }

        script.close();

        oarsub += " " + scriptName;

    } else {
        dtkError() << "no script and no application";
        return QString("ERROR");
    }

    // queue
    if (json.contains("queue")) {
        oarsub += " -q "+json["queue"].toString();
    }
    // options
    if (json.contains("options")) {
        oarsub += " "+json["options"].toString();
    }

    dtkDebug() << oarsub;
    QProcess stat; stat.start(oarsub);

    if (!stat.waitForStarted()) {
        dtkError() << "Unable to launch oarsub command";
        return QString("error");
    }

    if (!stat.waitForFinished()) {
        dtkError() << "Unable to completed oarsub command";
        return QString("error");
    }
    if (stat.exitCode() > 0) {
        QString error = stat.readAllStandardError();
        dtkError() << "Error running oarsub :" << error;
        return QString("error");
    } else {
        QString oarsubout = stat.readAll();

        QRegExp rx("OAR_JOB_ID=(\\d+)");
        int pos = rx.indexIn(oarsubout);
        QStringList jobid = rx.capturedTexts();

        Q_UNUSED(pos);

        dtkDebug() << jobid.at(1);
        return jobid.at(1);
    }
}

QString dtkDistributedResourceManagerOar::deljob(QString jobid)
{

    QString oardel = "oardel " + jobid;
    QProcess stat; stat.start(oardel);

    if (!stat.waitForStarted()) {
        dtkError() << "Unable to launch oardel command";
        return QString("ERROR");
    }

    if (!stat.waitForFinished()) {
        dtkError() << "Unable to complete oardel command";
        return QString("ERROR");
    }
    if (stat.exitCode() > 0) {
        QString error = stat.readAllStandardError();
        dtkError() << "Error running oardel :" << error;
        return QString("ERROR");
    } else {
        QString msg = stat.readAll();
        dtkDebug() << msg;
        return QString("OK");
    }
}

QByteArray dtkDistributedResourceManagerOar::status(void)
{
    QProcess stat;
    QString data;
    QVariantMap json;
    QVariantMap result;

    // get the jobs
    stat.start("oarstat -fJ");

    if (!stat.waitForStarted()) {
        dtkError() << "Unable to launch oarstat command";
        return QByteArray();
    }

    if (!stat.waitForFinished()) {
        dtkError() << "Unable to completed oarstat command";
        return QByteArray();
    }

    data = stat.readAll();

    QJsonDocument jsonDoc = QJsonDocument::fromJson(data.toUtf8());

    if (jsonDoc.isNull() || !jsonDoc.isObject()) {
        dtkError() << "Error while parsing JSON document (OAR) : not a json object" << data;
        return QByteArray();
    }
    json = jsonDoc.object().toVariantMap();

    stat.close();

    QVariantList jobs;
    QHash<QString, QString> activecores; //key is core id, value is jobid

    foreach(QVariant qv, json) {
        QVariantMap job = qv.toMap();
        QVariantMap dtkjob;
        QString id = job["Job_Id"].toString();
        QString user = job["job_user"].toString();
        QString queue = job["queue"].toString();
        QString qtime = job["submissionTime"].toString();
        QString stime = job["scheduledStart"].toString();
        QString walltime ;
        QString state =job["state"].toString();
        if (state == "Running")
            state = "running";
        else if ((state == "Waiting") && (job["reservation"].toString() == "scheduled"))
            state = "scheduled";
        else if (state == "Waiting")
            state = "queued";
        else if (state == "Suspended")
            state = "suspended";
        else if (state == "Hold")
            state = "blocked";
        else if (state == "Finishing")
            state = "exiting";
        else
            state = "unknown";

        foreach(QVariant coreid, job["assigned_resources"].toList()) {
            activecores[coreid.toString()] = id;
        }

        QRegExp rx("/network_address=(\\d+|ALL|BEST)(?:/core=)?(\\d+)?.*(?:walltime=)?(\\d+:\\d+:\\d+)");

        int pos = rx.indexIn(job["wanted_resources"].toString());

        Q_UNUSED(pos);

        QStringList resources_list = rx.capturedTexts();
        qlonglong nodes = resources_list.at(1).toInt();
        qlonglong cores = resources_list.at(2).toInt();
        if (cores == 0) {// all resources reserved
            cores = job["assigned_resources"].toList().count();
        }
        if (resources_list.count() > 3) {
            walltime = resources_list.at(3);
        } else {
            walltime = job["walltime"].toString(); //TODO: convert it to HH:MM:SS
            dtkDebug() << "can't find walltime from wanted resources! " << walltime;
        }

        QVariantMap jresources;

        jresources.insert("nodes",nodes);
        jresources.insert("cores",cores);

        dtkjob.insert("id", id);
        dtkjob.insert("username", user);
        dtkjob.insert("queue", queue);
        dtkjob.insert("queue_time", qtime);
        dtkjob.insert("start_time", stime);
        dtkjob.insert("walltime", walltime);
        dtkjob.insert("resources", jresources);
        dtkjob.insert("state", state);
        jobs << dtkjob;
        result.insert("jobs", jobs);
    }

    // Now get the nodes

    stat.start("oarnodes -J --sql \"host!=''\"");

    if (!stat.waitForStarted()) {
        dtkError() << "Unable to launch oarnodes command";
        return QByteArray();
    }

    if (!stat.waitForFinished()) {
        dtkError() << "Unable to completed oarnodes command";
        return QByteArray();
    }

    data = stat.readAll();

    jsonDoc = QJsonDocument::fromJson(data.toUtf8());

    if (jsonDoc.isNull() || !jsonDoc.isObject()) {
        dtkError() << "Error while parsing JSON document (OAR) : not a JSON object" << data;
        return QByteArray();
    }
    json = jsonDoc.object().toVariantMap();

    stat.close();

    QVariantMap nodes;
    foreach(QVariant qv, json) {
        QVariantMap jcore = qv.toMap();
        if (nodes.contains(jcore["host"].toString())) {
            QVariantMap core;
            QVariantMap node = nodes[jcore["host"].toString()].toMap();
            QVariantList cores = node["cores"].toList();
            QVariantList cpuids = node["cpuids"].toList();

            core.insert("id",jcore["resource_id"].toString());
            if (!activecores[core["id"].toString()].isEmpty()) {
                core.insert("job",activecores[core["id"].toString()]);
                int current_busy_cores = node["cores_busy"].toInt();
                node.insert("cores_busy", current_busy_cores+1);
            }
            qlonglong cpuid =  jcore["cpu"].toLongLong();
            if (!cpuids.contains(cpuid)) {
                cpuids <<  cpuid;
            }
            cores.append(core);
            node["cores"] = cores;
            node["cpuids"] = cpuids;
            nodes[jcore["host"].toString()] = node;
        } else { // new node
            QVariantList cores;
            QVariantList cpuids;
            QVariantList props;
            QVariantMap prop;
            QVariantMap core;
            QVariantMap node;
            if (jcore["cputype"].toString().contains("opteron")) {
                prop.insert("cpu_model","opteron");
                prop.insert("cpu_arch","x86_64");
            } else if (jcore["cputype"].toString().contains("xeon")) {
                prop.insert("cpu_model","xeon");
                prop.insert("cpu_arch","x86_64");
            }
            node.insert("name",jcore["host"]);
            QString state;
            if (jcore["state"].toString() == "Absent")
                if (jcore["available_upto"].toLongLong() > 0)
                    state = "standby";
                else
                    state = "absent";
            else if (jcore["state"].toString() == "Dead")
                state = "down";
            else if (jcore["state"].toString() == "Suspected")
                state = "absent";
            else if (jcore["state"].toString() == "Alive") {
                if (jcore["jobs"].toString().isEmpty())
                    state = "free";
                else
                    state = "busy";
            }
            node.insert("state", state);
            cpuids << jcore["cpu"].toLongLong();
            node.insert("cpuids",cpuids);
            core.insert("id",jcore["resource_id"]);
            if (!activecores[core["id"].toString()].isEmpty()) {
                core.insert("job",activecores[core["id"].toString()]);
                node.insert("cores_busy",1);
            } else {
                node.insert("cores_busy",0);
            }
            cores << core;
            props << prop;
            node.insert("cores",cores);
            node.insert("properties",props);
            nodes.insert(jcore["host"].toString(), node);
        }
    }

    QVariantList realnodes;
    // now we can compute the number of cpus per node
    foreach(QVariant qv, nodes) {
        QVariantMap map = qv.toMap();
        qlonglong cpus  = map["cpuids"].toList().count();
        qlonglong cores = map["cores"].toList().count();
        map.insert("cpus", cpus);
        map.remove("cpuids");
        realnodes << map;
    }
    result.insert("nodes", realnodes);

    return QJsonDocument(QJsonObject::fromVariantMap(result)).toJson();
}
<|endoftext|>


<commit_before>#include <arc/loader/Plugin.h>
#include <arc/message/PayloadSOAP.h>

#include <stdio.h>

#include "eqtlservice.h"

/**
 * Initializes the expression qtl service and returns it.
 */
static Arc::Plugin* get_service(Arc::PluginArgument* arg)
{
	Arc::ServicePluginArgument* mccarg = dynamic_cast<Arc::ServicePluginArgument*>(arg);
	if(!mccarg) return NULL;
	return new ArcService::ExpressionQtlService((Arc::Config*)(*mccarg));
}

/**
 * This PLUGINS_TABLE_NAME is defining basic entities of the implemented .
 * service. It is used to get the correct entry point to the plugin.
 * FORMAT: {name, kind, version, constructor}, null terminated
 */
Arc::PluginDescriptor PLUGINS_TABLE_NAME[] = {
	{"eQTL","HED:SERVICE",1,&get_service},
	{ NULL, NULL, 0, NULL }
};

using namespace Arc;

namespace ArcService
{

	ExpressionQtlService::ExpressionQtlService(Arc::Config *cfg) : Service(cfg),logger(Logger::rootLogger, "eQTL"),
	 mysql("eQTL_Stockholm","localhost","root","")
	{

		// synchronize this with eqtl_arc.wsdl
		ns_["arc"]="http://uni-luebeck.de/eqtl/arc/";

		//read config like this: prefix_=(std::string)((*cfg)["prefix"]);
	}

	ExpressionQtlService::~ExpressionQtlService(void)
	{
	}

	/**
	* Method which creates a fault payload
	*/
	Arc::MCC_Status ExpressionQtlService::makeFault(Arc::Message& outmsg, const std::string &reason)
	{
		logger.msg(Arc::WARNING, "Creating fault! Reason: \"%s\"",reason);
		// The boolean true indicates that inside of PayloadSOAP,
		// an object SOAPFault will be created inside.
		Arc::PayloadSOAP* outpayload = new Arc::PayloadSOAP(ns_,true);
		Arc::SOAPFault* fault = outpayload->Fault();
		if(fault) {
			fault->Code(Arc::SOAPFault::Sender);
			fault->Reason(reason);
		};
		outmsg.Payload(outpayload);

		return Arc::MCC_Status(Arc::STATUS_OK);
	}

	/**
	* Processes the incoming message and generates an outgoing message.
	* @param inmsg incoming message
	* @param outmsg outgoing message
	* @return Status of the result achieved
	*/
	Arc::MCC_Status ExpressionQtlService::process(Arc::Message& inmsg, Arc::Message& outmsg)
	{
		logger.msg(Arc::DEBUG, "eQTL service started...");

		/**  Extracting incoming payload */
		Arc::PayloadSOAP* inpayload  = NULL;
		try {
			inpayload = dynamic_cast<Arc::PayloadSOAP*>(inmsg.Payload());
		} catch(std::exception& e) { };
		if(!inpayload) {
			logger.msg(Arc::ERROR, "Input is not SOAP");
			return makeFault(outmsg, "Received message was not a valid SOAP message.");
		};
		/** */

		/** Analyzing and execute request */
/*
 <arc:QTL_FindByPosition>
         <!--Optional:-->
         <searchType>?</searchType>
         <searchRequest>
            <!--Optional:-->
            <lodScore>
               <from>?</from>
               <to>?</to>
            </lodScore>
            <!--Zero or more repetitions:-->
            <position>
               <chromosome>?</chromosome>
               <fromBP>?</fromBP>
               <toBP>?</toBP>
            </position>
            <!--Optional:-->
            <sameChromosome>?</sameChromosome>
            <!--Optional:-->
            <locusToGeneDistance>
               <from>?</from>
               <to>?</to>
            </locusToGeneDistance>
            <!--Optional:-->
            <orderBy>?</orderBy>
            <!--Optional:-->
            <maxNumResults>?</maxNumResults>
         </searchRequest>
      </arc:QTL_FindByPosition>
*/

		Arc::XMLNode requestNode  = inpayload->Child();
		logger.msg(Arc::DEBUG, "Called WSDL Operation: \"%s\"",requestNode.Name());
		if( requestNode.Name() == "QTL_FindByPosition" ) {
			std::string searchType = "both";
			if( requestNode["searchType"] ) searchType = (std::string) requestNode["searchType"];
			Arc::XMLNode searchRequest = requestNode["searchRequest"];
			std::string sql = "SELECT * FROM hajo_qtl_nocov WHERE 1 ";
			if( searchRequest["lodScore"]["fromBP"] ) {
				if(searchType == "
			}
		}

		Arc::XMLNode sayNode      = requestNode["echo:say"];
		std::string operation = (std::string) sayNode.Attribute("operation");
		std::string say       = (std::string) sayNode;
		std::string hear      = "";
		logger.msg(Arc::DEBUG, "Say: \"%s\"  Operation: \"%s\"",say,operation);
		/** */

		/** Create response */
		Arc::PayloadSOAP* outpayload = new Arc::PayloadSOAP(ns_);
		outpayload->NewChild("echo:echoResponse").NewChild("echo:hear")=hear;
		outmsg.Payload(outpayload);
		/** */

		logger.msg(Arc::DEBUG, "eQTL service done...");
		return Arc::MCC_Status(Arc::STATUS_OK);
	}

}//namespace<commit_msg>compiles + complete :) time for testing<commit_after>#include <arc/loader/Plugin.h>
#include <arc/message/PayloadSOAP.h>

#include <stdio.h>

#include "eqtlservice.h"

/**
 * Initializes the expression qtl service and returns it.
 */
static Arc::Plugin* get_service(Arc::PluginArgument* arg)
{
	Arc::ServicePluginArgument* mccarg = dynamic_cast<Arc::ServicePluginArgument*>(arg);
	if(!mccarg) return NULL;
	return new ArcService::ExpressionQtlService((Arc::Config*)(*mccarg));
}

/**
 * This PLUGINS_TABLE_NAME is defining basic entities of the implemented .
 * service. It is used to get the correct entry point to the plugin.
 * FORMAT: {name, kind, version, constructor}, null terminated
 */
Arc::PluginDescriptor PLUGINS_TABLE_NAME[] = {
	{"eQTL","HED:SERVICE",1,&get_service},
	{ NULL, NULL, 0, NULL }
};

using namespace Arc;

namespace ArcService
{

	ExpressionQtlService::ExpressionQtlService(Arc::Config *cfg) : Service(cfg),logger(Logger::rootLogger, "eQTL"),
	 mysql("eQTL_Stockholm","localhost","root","")
	{

		// synchronize this with eqtl_arc.wsdl
		ns_["arc"]="http://uni-luebeck.de/eqtl/arc/";

		//read config like this: prefix_=(std::string)((*cfg)["prefix"]);
	}

	ExpressionQtlService::~ExpressionQtlService(void)
	{
	}

	/**
	* Method which creates a fault payload
	*/
	Arc::MCC_Status ExpressionQtlService::makeFault(Arc::Message& outmsg, const std::string &reason)
	{
		logger.msg(Arc::WARNING, "Creating fault! Reason: \"%s\"",reason);
		// The boolean true indicates that inside of PayloadSOAP,
		// an object SOAPFault will be created inside.
		Arc::PayloadSOAP* outpayload = new Arc::PayloadSOAP(ns_,true);
		Arc::SOAPFault* fault = outpayload->Fault();
		if(fault) {
			fault->Code(Arc::SOAPFault::Sender);
			fault->Reason(reason);
		};
		outmsg.Payload(outpayload);

		return Arc::MCC_Status(Arc::STATUS_OK);
	}

	/**
	* Processes the incoming message and generates an outgoing message.
	* @param inmsg incoming message
	* @param outmsg outgoing message
	* @return Status of the result achieved
	*/
	Arc::MCC_Status ExpressionQtlService::process(Arc::Message& inmsg, Arc::Message& outmsg)
	{
		logger.msg(Arc::DEBUG, "eQTL service started...");

		/**  Extracting incoming payload */
		Arc::PayloadSOAP* inpayload  = NULL;
		try {
			inpayload = dynamic_cast<Arc::PayloadSOAP*>(inmsg.Payload());
		} catch(std::exception& e) { };
		if(!inpayload) {
			logger.msg(Arc::ERROR, "Input is not SOAP");
			return makeFault(outmsg, "Received message was not a valid SOAP message.");
		};
		/** */

		/** Analyzing and execute request */
		Arc::PayloadSOAP* outpayload = new Arc::PayloadSOAP(ns_);

		Arc::XMLNode requestNode  = inpayload->Child();
		logger.msg(Arc::DEBUG, "Called WSDL Operation: \"%s\"",requestNode.Name());
		if( requestNode.Name() == "QTL_FindByPosition" ) {
			bool searchMarker = true;
			bool searchGene = true;
			if( requestNode["searchType"] ) {
				std::string searchType = (std::string) requestNode["searchType"];
				if(searchType == "marker") searchGene = false;
				if(searchType == "gene") searchMarker = false;
			}
			Arc::XMLNode searchRequest = requestNode["searchRequest"];
			std::ostringstream sql;
			sql << "SELECT * FROM hajo_qtl_nocov WHERE 1 ";

			if( searchRequest["lodScore"]["from"] )
				sql << " AND lod >= " << mysqlpp::quote << (std::string) searchRequest["lodScore"]["from"];
			if( searchRequest["lodScore"]["to"] )
				sql << " AND lod <= " << mysqlpp::quote << (std::string) searchRequest["lodScore"]["to"];

			Arc::XMLNode position = searchRequest["position"];
			if( position ) {
				sql << " AND ( FALSE ";

				while(position) {
					if( searchMarker ) {
						sql << " OR ( marker_chromosome=" << mysqlpp::quote << (std::string) position["chromosome"];
						if( position["fromBP"] )
							sql << " AND marker_positionBP >= " << mysqlpp::quote << (std::string) position["fromBP"];
						if( position["toBP"] )
							sql << " AND marker_positionBP <= " << mysqlpp::quote << (std::string) position["toBP"];
						sql << ") ";
					}
					if( searchGene ) {
						sql << " OR ( genePosition_chromosome=" << mysqlpp::quote << (std::string) position["chromosome"];
						if( position["fromBP"] )
							sql << " AND genePosition_toBP >= " << mysqlpp::quote << (std::string) position["fromBP"];
						if( position["toBP"] )
							sql << " AND genePosition_fromBP <= " << mysqlpp::quote << (std::string) position["toBP"];
						sql << ") ";
					}
					++position;
				}
				sql << " ) ";
			}

			if( searchRequest["sameChromosome"] ) {
				int what = atoi( ((std::string) searchRequest["sameChromosome"]).c_str() );
				if( what == 1 ) sql << " AND sameChromosome='1' ";
				else if( what == -1 ) sql << " AND sameChromosome='0' ";
			}

			if( searchRequest["locusToGeneDistance"]["from"] )
				sql << " AND locusToGeneDistance >= " << mysqlpp::quote << (std::string) searchRequest["locusToGeneDistance"]["from"];
			if( searchRequest["locusToGeneDistance"]["to"] )
				sql << " AND locusToGeneDistance <= " << mysqlpp::quote << (std::string) searchRequest["locusToGeneDistance"]["to"];

			std::string orderBy = "lod";
			if( searchRequest["orderBy"] ) {
				std::string order = searchRequest["orderBy"];
				if( order == "LodScore" ) orderBy = "lod";
			}
			sql << " ORDER BY ", orderBy;
			if( searchRequest["maxNumResults"] )
				sql << " LIMIT "<< mysqlpp::quote << (std::string) searchRequest["maxNumResults"];

			std::string sqlstring = sql.str();
			logger.msg(Arc::DEBUG, "SQL Query: \"%s\"",sqlstring);
			mysqlpp::Query query = mysql.query(sqlstring);
			mysqlpp::StoreQueryResult res = query.store();
			logger.msg(Arc::DEBUG, "Number of results: \"%d\"",res.num_rows());

			Arc::XMLNode addToMe = outpayload->NewChild("arc:QTL_FindByPositionResponse");
			for(size_t i=0;i<res.num_rows();i++) {
				Arc::XMLNode curAdd = addToMe.NewChild("qtls");
				curAdd.NewChild("lod") = res[i]["lod"];
				curAdd.NewChild("marker");
				curAdd["marker"].NewChild("name") = res[i]["marker_name"];
				curAdd["marker"].NewChild("chromosome") = res[i]["marker_chromosome"];
				curAdd["marker"].NewChild("positionBP") = res[i]["marker_positionBP"];
				curAdd.NewChild("genePosition");
				curAdd["genePosition"].NewChild("chromosome") = res[i]["genePosition_chromosome"];
				curAdd["genePosition"].NewChild("fromBP") = res[i]["genePosition_fromBP"];
				curAdd["genePosition"].NewChild("toBP") = res[i]["genePosition_toBP"];
				curAdd.NewChild("geneEntrezID") = res[i]["geneEntrezID"];
				curAdd.NewChild("statistics");
				curAdd["statistics"].NewChild("mean") = res[i]["statistics_mean"];
				curAdd["statistics"].NewChild("sd") = res[i]["statistics_sd"];
				curAdd["statistics"].NewChild("median") = res[i]["statistics_median"];
				curAdd["statistics"].NewChild("variance") = res[i]["statistics_variance"];
			}
		}

		logger.msg(Arc::DEBUG, "eQTL service done...");
		outmsg.Payload(outpayload);
		return Arc::MCC_Status(Arc::STATUS_OK);
	}

}//namespace<|endoftext|>


<commit_before>#include "runner_babylon.h"

#include <babylon/asio/asio.h>
#include <babylon/core/filesystem.h>
#include <babylon/babylon_common.h>
#include <glad/glad.h>
#include "imgui_utils/icons_font_awesome_5.h"
#include <imgui_utils/imgui_utils.h>
#include "imgui_utils/imgui_runner/runner_glfw.h"
#include "imgui_utils/imgui_runner/runner_sdl.h"
#include "imgui_utils/imgui_runner/runner_emscripten.h"
#include <iostream>

namespace ImGuiUtils
{
namespace ImGuiRunner {
namespace runner_babylon_details
{
static ImFont* _fontRegular = nullptr;
static ImFont* _fontSolid = nullptr;

void LoadFontAwesome()
{
  // Loads fonts
  ImGuiIO& io = ImGui::GetIO();
  io.Fonts->AddFontDefault();
  static ImWchar ranges[] = { 0xf000, 0xf82f, 0 };
  ImFontConfig config;
  config.MergeMode = true;
  auto fontRegularPath
    = std::string(BABYLON::assets_folder() + "/fonts/") + FONT_ICON_FILE_NAME_FAR;
  if (BABYLON::Filesystem::isFile(fontRegularPath))
  {
    _fontRegular = io.Fonts->AddFontFromFileTTF(fontRegularPath.c_str(),
                                                ImGui::IconSize, &config, ranges);
    printf("Found font file %s", fontRegularPath.c_str());
  }
  else
  {
    printf("Could not read font file %s", fontRegularPath.c_str());
  }

  auto fontSolidPath
    = std::string(BABYLON::assets_folder() + "/fonts/") + FONT_ICON_FILE_NAME_FAS;
  if (BABYLON::Filesystem::isFile(fontSolidPath))
  {
    _fontSolid = io.Fonts->AddFontFromFileTTF(fontSolidPath.c_str(),
                                              ImGui::IconSize, &config, ranges);
    printf("Found font file %s", fontSolidPath.c_str());
  }
  else
  {
    printf("Could not read font file %s", fontSolidPath.c_str());
  }

}

void ImplProvideFullScreenWindow(const AppWindowParams& appWindowParams)
{
  ImGui::SetNextWindowPos(ImVec2(0, 0));
  ImVec2 winSize = ImGui::GetIO().DisplaySize;
  // winSize.y -= 10.f;
  ImGui::SetNextWindowSize(winSize);
  ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDecoration
                                 | ImGuiWindowFlags_NoScrollWithMouse
                                 | ImGuiWindowFlags_NoBringToFrontOnFocus;
  if (appWindowParams.ShowMenuBar)
    windowFlags |= ImGuiWindowFlags_MenuBar;
  ImGui::Begin("Main window (title bar invisible)", nullptr, windowFlags);
}

ImGuiID MainDockSpaceId()
{
  static ImGuiID id = ImGui::GetID("MainDockSpace");
  return id;
}

void ImplProvideFullScreenDockSpace(const AppWindowParams& appWindowParams)
{
  ImGuiViewport* viewport = ImGui::GetMainViewport();
  ImGui::SetNextWindowPos(viewport->Pos);
  ImGui::SetNextWindowSize(viewport->Size);
  ImGui::SetNextWindowViewport(viewport->ID);
  ImGui::SetNextWindowBgAlpha(0.0f);

  ImGuiWindowFlags window_flags
    = ImGuiWindowFlags_NoDocking;
  window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse
                  | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
  window_flags
    |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
  if (appWindowParams.ShowMenuBar)
    window_flags |= ImGuiWindowFlags_MenuBar;

  ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
  ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
  ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
  static bool p_open = true;
  ImGui::Begin(appWindowParams.Title.c_str(), &p_open, window_flags);
  ImGui::PopStyleVar(3);

  ImGuiID dockspace_id = MainDockSpaceId();
  ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode; // ImGuiDockNodeFlags_PassthruDockspace;
  ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
}

bool gWasDockLayoutDone = false;

bool WasDockLayoutDone()
{
  return gWasDockLayoutDone;
}
void SetDockLayout_Done()
{
  gWasDockLayoutDone = true;
}
void SetDockLayout_NotDone()
{
  remove("imgui.ini");
  gWasDockLayoutDone = false;
}

} // namespace runner_babylon_details

RunnerBabylon::RunnerBabylon(
  std::unique_ptr<ImGui::ImGuiRunner::AbstractRunner> abstractRunner,
  const AppWindowParams& appWindowParams,
  GuiFunctionWithExit guiFunctionWithExit,
  PostInitFunction postInitFunction)
  : mAbstractRunner(std::move(abstractRunner))
  , mAppWindowParams(appWindowParams)
  , mGuiFunctionWithExit(guiFunctionWithExit)
  , mPostInitFunction(postInitFunction)
{
  DoInit();
}

void RunnerBabylon::DoInit()
{
  mAbstractRunner->SetBackendFullScreen(mAppWindowParams.FullScreen);
  mAbstractRunner->SetBackendWindowTitle(mAppWindowParams.Title);
  mAbstractRunner->SetBackendWindowSize(ImVec2((float)mAppWindowParams.Width, (float)mAppWindowParams.Height) );

  if (mAppWindowParams.WindowedFullScreen)
  {
    ImVec2 winSize;
    winSize.x = (float)ImGui::ImGuiRunner::MainScreenResolution().x;
    winSize.y = (float)ImGui::ImGuiRunner::MainScreenResolution().y - mAppWindowParams.WindowedFullScreen_HeightReduce;
    mAbstractRunner->SetBackendWindowSize(winSize);
  }

  mAbstractRunner->SetClearColor(mAppWindowParams.ClearColor);

  mAbstractRunner->LoadFonts = runner_babylon_details::LoadFontAwesome;

  std::function<void(void)> postInit = [this]() {
    if (mAppWindowParams.DefaultWindowType == DefaultWindowTypeOption::ProvideFullScreenDockSpace)
      ImGui::GetIO().ConfigFlags = ImGui::GetIO().ConfigFlags | ImGuiConfigFlags_DockingEnable;
    mPostInitFunction();
    ImGui::GetIO().ConfigWindowsMoveFromTitleBarOnly = mAppWindowParams.ConfigWindowsMoveFromTitleBarOnly;
  };

  std::function<void(void)> provideWindowOrDock = [this](){
    if (mAppWindowParams.DefaultWindowType == DefaultWindowTypeOption::ProvideFullScreenWindow)
      runner_babylon_details::ImplProvideFullScreenWindow(mAppWindowParams);

    if (mAppWindowParams.DefaultWindowType == DefaultWindowTypeOption::ProvideFullScreenDockSpace)
    {
      if (!runner_babylon_details::WasDockLayoutDone())
      {
        if (mAppWindowParams.InitialDockLayoutFunction)
          mAppWindowParams.InitialDockLayoutFunction(runner_babylon_details::MainDockSpaceId());
        runner_babylon_details::SetDockLayout_Done();
      }
      runner_babylon_details::ImplProvideFullScreenDockSpace(mAppWindowParams);
    }
  };

  auto guiFunctionWithExitCopy = mGuiFunctionWithExit;
  std::function<bool(void)> showGui =
    [this, postInit, provideWindowOrDock, guiFunctionWithExitCopy]
    () {
    static bool postInited = false;
    if (!postInited)
    {
      postInited = true;
      postInit();
    }
    provideWindowOrDock();
    bool shouldExit = guiFunctionWithExitCopy();

    if (mAppWindowParams.DefaultWindowType != DefaultWindowTypeOption::NoDefaultWindow) {
      ImGui::End();
    }
    return shouldExit;
  };

  mAbstractRunner->ShowGui = showGui;
}

void RunnerBabylon::Run()
{
  mAbstractRunner->Run();
}

void RunnerBabylon::ResetDockLayout()
{
  runner_babylon_details::SetDockLayout_NotDone();
}

#ifdef IMGUI_RUNNER_USE_GLFW
void InvokeRunnerBabylonGlfw(const AppWindowParams& appWindowParams,
                             GuiFunctionWithExit guiFunctionWithExit,
                             PostInitFunction postInitFunction)
{
  auto runner = std::make_unique<ImGui::ImGuiRunner::RunnerGlfw>();
  auto runner_babylon = RunnerBabylon(
    std::move(runner),
    appWindowParams,
    guiFunctionWithExit,
    postInitFunction
    );
  runner_babylon.Run();
  BABYLON::asio::Service_Stop();
}
#endif

#ifdef IMGUI_RUNNER_USE_SDL
void InvokeRunnerBabylonSdl(const AppWindowParams& appWindowParams,
                             GuiFunctionWithExit guiFunctionWithExit,
                             PostInitFunction postInitFunction)
{
  auto runner = std::make_unique<ImGui::ImGuiRunner::RunnerSdl>();
  auto runner_babylon = RunnerBabylon(
    std::move(runner),
    appWindowParams,
    guiFunctionWithExit,
    postInitFunction
  );
  runner_babylon.Run();
  BABYLON::asio::Service_Stop();
}
#endif

#ifdef EMSCRIPTEN
// With emscripten we will run an external loop, so that we need to keep a global variable
std::unique_ptr<RunnerBabylon> gRunnerBabylon;

void InvokeRunnerBabylonEmscripten(const AppWindowParams& appWindowParams,
                                   GuiFunctionWithExit guiFunctionWithExit,
                                   PostInitFunction postInitFunction)
{
  auto runner = std::make_unique<ImGui::ImGuiRunner::RunnerEmscripten>();
  gRunnerBabylon = std::make_unique<RunnerBabylon>(
    std::move(runner),
    appWindowParams,
    guiFunctionWithExit,
    postInitFunction
  );
  gRunnerBabylon->Run();
  BABYLON::asio::Service_Stop();
}
#endif

void InvokeRunnerBabylon(const AppWindowParams& appWindowParams,
                         GuiFunctionWithExit guiFunctionWithExit,
                         PostInitFunction postInitFunction)
{
#ifdef EMSCRIPTEN
  InvokeRunnerBabylonEmscripten(appWindowParams, guiFunctionWithExit, postInitFunction);
#elif defined(IMGUI_RUNNER_USE_SDL)
  InvokeRunnerBabylonSdl(appWindowParams, guiFunctionWithExit, postInitFunction);
#elif defined(IMGUI_RUNNER_USE_GLFW)
  InvokeRunnerBabylonGlfw(appWindowParams, guiFunctionWithExit, postInitFunction);
#else
  #error "InvokeRunnerBabylon: Not Backend available!"
#endif
}

} // namespace ImGuiRunner
} // namespace ImGuiUtils
<commit_msg>correct font loading for emscripten<commit_after>#include "runner_babylon.h"

#include <babylon/asio/asio.h>
#include <babylon/core/filesystem.h>
#include <babylon/babylon_common.h>
#include <glad/glad.h>
#include "imgui_utils/icons_font_awesome_5.h"
#include <imgui_utils/imgui_utils.h>
#include "imgui_utils/imgui_runner/runner_glfw.h"
#include "imgui_utils/imgui_runner/runner_sdl.h"
#include "imgui_utils/imgui_runner/runner_emscripten.h"
#include <iostream>

namespace ImGuiUtils
{
namespace ImGuiRunner {
namespace runner_babylon_details
{
static ImFont* _fontRegular = nullptr;
static ImFont* _fontSolid = nullptr;

void LoadFontAwesome()
{
  // Loads fonts
  ImGuiIO& io = ImGui::GetIO();
  io.Fonts->AddFontDefault();
  static ImWchar ranges[] = { 0xf000, 0xf82f, 0 };
  ImFontConfig config;
  config.MergeMode = true;

  std::string fontFolder;
#ifdef __EMSCRIPTEN__
  fontFolder = std::string("emscripten_static_assets_folder/fonts/");
#else
  fontFolder = BABYLON::assets_folder() + "/fonts/";
#endif

  auto fontRegularPath
    = fontFolder + FONT_ICON_FILE_NAME_FAR;
  if (BABYLON::Filesystem::isFile(fontRegularPath))
  {
    _fontRegular = io.Fonts->AddFontFromFileTTF(fontRegularPath.c_str(),
                                                ImGui::IconSize, &config, ranges);
    printf("Found font file %s", fontRegularPath.c_str());
  }
  else
  {
    printf("Could not read font file %s", fontRegularPath.c_str());
  }

  auto fontSolidPath
    = fontFolder + FONT_ICON_FILE_NAME_FAS;
  if (BABYLON::Filesystem::isFile(fontSolidPath))
  {
    _fontSolid = io.Fonts->AddFontFromFileTTF(fontSolidPath.c_str(),
                                              ImGui::IconSize, &config, ranges);
    printf("Found font file %s", fontSolidPath.c_str());
  }
  else
  {
    printf("Could not read font file %s", fontSolidPath.c_str());
  }

}

void ImplProvideFullScreenWindow(const AppWindowParams& appWindowParams)
{
  ImGui::SetNextWindowPos(ImVec2(0, 0));
  ImVec2 winSize = ImGui::GetIO().DisplaySize;
  // winSize.y -= 10.f;
  ImGui::SetNextWindowSize(winSize);
  ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDecoration
                                 | ImGuiWindowFlags_NoScrollWithMouse
                                 | ImGuiWindowFlags_NoBringToFrontOnFocus;
  if (appWindowParams.ShowMenuBar)
    windowFlags |= ImGuiWindowFlags_MenuBar;
  ImGui::Begin("Main window (title bar invisible)", nullptr, windowFlags);
}

ImGuiID MainDockSpaceId()
{
  static ImGuiID id = ImGui::GetID("MainDockSpace");
  return id;
}

void ImplProvideFullScreenDockSpace(const AppWindowParams& appWindowParams)
{
  ImGuiViewport* viewport = ImGui::GetMainViewport();
  ImGui::SetNextWindowPos(viewport->Pos);
  ImGui::SetNextWindowSize(viewport->Size);
  ImGui::SetNextWindowViewport(viewport->ID);
  ImGui::SetNextWindowBgAlpha(0.0f);

  ImGuiWindowFlags window_flags
    = ImGuiWindowFlags_NoDocking;
  window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse
                  | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
  window_flags
    |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
  if (appWindowParams.ShowMenuBar)
    window_flags |= ImGuiWindowFlags_MenuBar;

  ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
  ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
  ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
  static bool p_open = true;
  ImGui::Begin(appWindowParams.Title.c_str(), &p_open, window_flags);
  ImGui::PopStyleVar(3);

  ImGuiID dockspace_id = MainDockSpaceId();
  ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode; // ImGuiDockNodeFlags_PassthruDockspace;
  ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
}

bool gWasDockLayoutDone = false;

bool WasDockLayoutDone()
{
  return gWasDockLayoutDone;
}
void SetDockLayout_Done()
{
  gWasDockLayoutDone = true;
}
void SetDockLayout_NotDone()
{
  remove("imgui.ini");
  gWasDockLayoutDone = false;
}

} // namespace runner_babylon_details

RunnerBabylon::RunnerBabylon(
  std::unique_ptr<ImGui::ImGuiRunner::AbstractRunner> abstractRunner,
  const AppWindowParams& appWindowParams,
  GuiFunctionWithExit guiFunctionWithExit,
  PostInitFunction postInitFunction)
  : mAbstractRunner(std::move(abstractRunner))
  , mAppWindowParams(appWindowParams)
  , mGuiFunctionWithExit(guiFunctionWithExit)
  , mPostInitFunction(postInitFunction)
{
  DoInit();
}

void RunnerBabylon::DoInit()
{
  mAbstractRunner->SetBackendFullScreen(mAppWindowParams.FullScreen);
  mAbstractRunner->SetBackendWindowTitle(mAppWindowParams.Title);
  mAbstractRunner->SetBackendWindowSize(ImVec2((float)mAppWindowParams.Width, (float)mAppWindowParams.Height) );

  if (mAppWindowParams.WindowedFullScreen)
  {
    ImVec2 winSize;
    winSize.x = (float)ImGui::ImGuiRunner::MainScreenResolution().x;
    winSize.y = (float)ImGui::ImGuiRunner::MainScreenResolution().y - mAppWindowParams.WindowedFullScreen_HeightReduce;
    mAbstractRunner->SetBackendWindowSize(winSize);
  }

  mAbstractRunner->SetClearColor(mAppWindowParams.ClearColor);

  mAbstractRunner->LoadFonts = runner_babylon_details::LoadFontAwesome;

  std::function<void(void)> postInit = [this]() {
    if (mAppWindowParams.DefaultWindowType == DefaultWindowTypeOption::ProvideFullScreenDockSpace)
      ImGui::GetIO().ConfigFlags = ImGui::GetIO().ConfigFlags | ImGuiConfigFlags_DockingEnable;
    mPostInitFunction();
    ImGui::GetIO().ConfigWindowsMoveFromTitleBarOnly = mAppWindowParams.ConfigWindowsMoveFromTitleBarOnly;
  };

  std::function<void(void)> provideWindowOrDock = [this](){
    if (mAppWindowParams.DefaultWindowType == DefaultWindowTypeOption::ProvideFullScreenWindow)
      runner_babylon_details::ImplProvideFullScreenWindow(mAppWindowParams);

    if (mAppWindowParams.DefaultWindowType == DefaultWindowTypeOption::ProvideFullScreenDockSpace)
    {
      if (!runner_babylon_details::WasDockLayoutDone())
      {
        if (mAppWindowParams.InitialDockLayoutFunction)
          mAppWindowParams.InitialDockLayoutFunction(runner_babylon_details::MainDockSpaceId());
        runner_babylon_details::SetDockLayout_Done();
      }
      runner_babylon_details::ImplProvideFullScreenDockSpace(mAppWindowParams);
    }
  };

  auto guiFunctionWithExitCopy = mGuiFunctionWithExit;
  std::function<bool(void)> showGui =
    [this, postInit, provideWindowOrDock, guiFunctionWithExitCopy]
    () {
    static bool postInited = false;
    if (!postInited)
    {
      postInited = true;
      postInit();
    }
    provideWindowOrDock();
    bool shouldExit = guiFunctionWithExitCopy();

    if (mAppWindowParams.DefaultWindowType != DefaultWindowTypeOption::NoDefaultWindow) {
      ImGui::End();
    }
    return shouldExit;
  };

  mAbstractRunner->ShowGui = showGui;
}

void RunnerBabylon::Run()
{
  mAbstractRunner->Run();
}

void RunnerBabylon::ResetDockLayout()
{
  runner_babylon_details::SetDockLayout_NotDone();
}

#ifdef IMGUI_RUNNER_USE_GLFW
void InvokeRunnerBabylonGlfw(const AppWindowParams& appWindowParams,
                             GuiFunctionWithExit guiFunctionWithExit,
                             PostInitFunction postInitFunction)
{
  auto runner = std::make_unique<ImGui::ImGuiRunner::RunnerGlfw>();
  auto runner_babylon = RunnerBabylon(
    std::move(runner),
    appWindowParams,
    guiFunctionWithExit,
    postInitFunction
    );
  runner_babylon.Run();
  BABYLON::asio::Service_Stop();
}
#endif

#ifdef IMGUI_RUNNER_USE_SDL
void InvokeRunnerBabylonSdl(const AppWindowParams& appWindowParams,
                             GuiFunctionWithExit guiFunctionWithExit,
                             PostInitFunction postInitFunction)
{
  auto runner = std::make_unique<ImGui::ImGuiRunner::RunnerSdl>();
  auto runner_babylon = RunnerBabylon(
    std::move(runner),
    appWindowParams,
    guiFunctionWithExit,
    postInitFunction
  );
  runner_babylon.Run();
  BABYLON::asio::Service_Stop();
}
#endif

#ifdef EMSCRIPTEN
// With emscripten we will run an external loop, so that we need to keep a global variable
std::unique_ptr<RunnerBabylon> gRunnerBabylon;

void InvokeRunnerBabylonEmscripten(const AppWindowParams& appWindowParams,
                                   GuiFunctionWithExit guiFunctionWithExit,
                                   PostInitFunction postInitFunction)
{
  auto runner = std::make_unique<ImGui::ImGuiRunner::RunnerEmscripten>();
  gRunnerBabylon = std::make_unique<RunnerBabylon>(
    std::move(runner),
    appWindowParams,
    guiFunctionWithExit,
    postInitFunction
  );
  gRunnerBabylon->Run();
  BABYLON::asio::Service_Stop();
}
#endif

void InvokeRunnerBabylon(const AppWindowParams& appWindowParams,
                         GuiFunctionWithExit guiFunctionWithExit,
                         PostInitFunction postInitFunction)
{
#ifdef EMSCRIPTEN
  InvokeRunnerBabylonEmscripten(appWindowParams, guiFunctionWithExit, postInitFunction);
#elif defined(IMGUI_RUNNER_USE_SDL)
  InvokeRunnerBabylonSdl(appWindowParams, guiFunctionWithExit, postInitFunction);
#elif defined(IMGUI_RUNNER_USE_GLFW)
  InvokeRunnerBabylonGlfw(appWindowParams, guiFunctionWithExit, postInitFunction);
#else
  #error "InvokeRunnerBabylon: Not Backend available!"
#endif
}

} // namespace ImGuiRunner
} // namespace ImGuiUtils
<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/liveness_util.h"

#include <algorithm>
#include <utility>
#include <vector>

#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/logical_buffer.h"
#include "tensorflow/compiler/xla/service/tuple_points_to_analysis.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/compiler/xla/types.h"
#include "tensorflow/compiler/xla/util.h"

namespace xla {

bool DoesNotUseOperandBuffer(const HloInstruction* operand,
                             const ShapeIndex& index,
                             const HloInstruction* user,
                             const TuplePointsToAnalysis& points_to_analysis) {
  CHECK(user->IsUserOf(operand))
      << "user: " << user->ToString() << " operand: " << operand->ToString();
  if (user->opcode() == HloOpcode::kGetTupleElement && !index.empty()) {
    // GetTupleElement instructions only access the top-level buffer of their
    // operand.
    return true;
  } else if (user->opcode() == HloOpcode::kFusion &&
             user->fusion_kind() == HloInstruction::FusionKind::kLoop) {
    // Find fusion parameter associated with 'operand'.
    auto it = std::find_if(
        user->fused_parameters().begin(), user->fused_parameters().end(),
        [=](HloInstruction* fused_param) {
          return user->operand(fused_param->parameter_number()) == operand;
        });
    CHECK(it != user->fused_parameters().end());
    // Iterate through all users of all buffer aliases of the buffer in the
    // points-to set of fusion parameter at 'index'.
    // Return false if any uses are detected at 'index', returns true otherwise.
    const LogicalBuffer* buffer =
        points_to_analysis.GetBufferDefinedAt(*it, index).ValueOrDie();
    for (const BufferAlias& alias :
         points_to_analysis.GetBufferAliases(*buffer)) {
      for (HloInstruction* alias_user : alias.instruction()->users()) {
        if (DoesNotUseOperandBuffer(alias.instruction(), alias.index(),
                                    alias_user, points_to_analysis)) {
          continue;
        }
        // Return false: use detected at 'buffer' -> 'alias' -> 'alias_user'.
        return false;
      }
    }
    // Return true: found no uses of 'operand' at 'index' in 'user'.
    return true;
  }
  return false;
}

namespace {

// Returns all uses of all aliases of 'instruction' at 'index' in 'uses'.
// Each use in 'uses' is a pair (HloInstruction* user, int64 operand_index)
// where 'user' is a user of an alias of 'intruction' at 'index', and
// 'operand_index' is the operand index at which the alias appears in the
// operand list of 'user'.
std::vector<std::pair<HloInstruction*, int64>> GetAllUsesOfInstructionAtIndex(
    HloInstruction* instruction, const ShapeIndex& index,
    const TuplePointsToAnalysis& points_to_analysis) {
  std::vector<std::pair<HloInstruction*, int64>> uses;
  const std::vector<const LogicalBuffer*>& points_to =
      points_to_analysis.GetPointsToSet(instruction).element(index);
  for (const LogicalBuffer* buffer : points_to) {
    for (const BufferAlias& alias :
         points_to_analysis.GetBufferAliases(*buffer)) {
      for (HloInstruction* alias_user : alias.instruction()->users()) {
        if (DoesNotUseOperandBuffer(alias.instruction(), alias.index(),
                                    alias_user, points_to_analysis)) {
          continue;
        }
        for (int64 op_idx : alias_user->OperandIndices(alias.instruction())) {
          uses.emplace_back(alias_user, op_idx);
        }
      }
    }
  }
  return uses;
}

// Returns true if there is exactly one use of 'operand' at 'operand_index'
// in 'fusion.fused_instructions', where the singleton use is the fused
// root at operand index 'use_operand_index'. Returns false otherwise.
//
// REQUIRES: 'fusion' opcode is a kFusion instruction.
bool HasUniqueFusedUseOfOperandAt(
    HloInstruction* operand, const ShapeIndex& operand_index,
    HloInstruction* fusion, const int64 use_operand_index,
    const TuplePointsToAnalysis& points_to_analysis) {
  CHECK_EQ(HloOpcode::kFusion, fusion->opcode());
  // Check that 'operand' is unique in the operand list of 'fusion'.
  if (fusion->OperandIndices(operand).size() > 1) {
    return false;
  }
  // Find fusion parameter associated with 'operand'.
  const auto& fused_params = fusion->fused_parameters();
  auto fused_param_it = std::find_if(
      fused_params.begin(), fused_params.end(),
      [&](HloInstruction* fused_param) {
        return fusion->operand(fused_param->parameter_number()) == operand;
      });
  if (fused_param_it == fused_params.end()) {
    return false;
  }
  auto* fused_param = *fused_param_it;
  // Get all uses of 'operand' at 'index' from 'fusion.fused_instructions'.
  auto fused_param_uses = GetAllUsesOfInstructionAtIndex(
      fused_param, operand_index, points_to_analysis);
  // Return true iff there is exactly one use of 'operand' at 'index', and
  // this singleton use is the fused root (at index in 'use_operand_indices').
  return fused_param_uses.size() == 1 &&
         fused_param_uses[0].first == fusion->fused_expression_root() &&
         fused_param_uses[0].second == use_operand_index;
}

}  // namespace

// User and operand can share buffers iff both instructions emit the same shape
// and layout, and 'user' meets one of the following qualifications:
//
// (1) Is element-wise. Or...
// (2) Is a loop fusion instruction where the only use of 'operand' at 'index'
//     in the set 'user.fused_instructions' is a DynamicUpdateSlice fused root
//     at operand 0. Or...
// (3) Is a kDot -> kAdd (or fused kTransposeDot -> kAdd) output fusion
//     instruction where the only use of 'operand' at 'index' in the set
//     'user.fused_instructions' is a kAdd fused root at operand 0 or 1. Or...
// (4) The 'user' of 'operand' is DynamicUpdateSlice or While at operand index
//     0.
//
// (2) and (3) can only be determined if points-to analysis is available.
bool CanShareOperandBufferWithUser(
    HloInstruction* operand, const ShapeIndex& operand_index,
    HloInstruction* user, const ShapeIndex& user_index,
    const TuplePointsToAnalysis* points_to_analysis) {
  CHECK(user->IsUserOf(operand))
      << "user: " << user->ToString() << " operand: " << operand->ToString();
  Shape operand_subshape =
      ShapeUtil::GetSubshape(operand->shape(), operand_index);
  Shape user_subshape = ShapeUtil::GetSubshape(user->shape(), user_index);
  // Check that operand and user emit the same shape and layout.
  if (!ShapeUtil::Equal(operand_subshape, user_subshape)) {
    return false;
  }
  if (points_to_analysis != nullptr && user->opcode() == HloOpcode::kFusion) {
    if (user->fusion_kind() == HloInstruction::FusionKind::kLoop &&
        user->fused_expression_root()->opcode() ==
            HloOpcode::kDynamicUpdateSlice) {
      // Loop fusion with kDynamicUpdateSlice fused root.
      //
      // Returns true iff there is exactly one use of 'operand' at shape index
      // 'operand_index', and this singleton use is the fused root at operand
      // index 0.
      return HasUniqueFusedUseOfOperandAt(operand, operand_index, user, 0,
                                          *points_to_analysis);
    } else if (user->fusion_kind() == HloInstruction::FusionKind::kOutput &&
               user->fused_expression_root()->opcode() == HloOpcode::kAdd) {
      // Output fusion with kAdd fused root.

      // Check if one operand of kAdd fused root is either kDot, or nested
      // kFusion of kind kTransposeDot.
      auto* add = user->fused_expression_root();
      auto add_operand_it =
          std::find_if(add->operands().begin(), add->operands().end(),
                       [&](HloInstruction* operand) {
                         return operand->opcode() == HloOpcode::kDot ||
                                (operand->opcode() == HloOpcode::kFusion &&
                                 operand->fusion_kind() ==
                                     HloInstruction::FusionKind::kTransposeDot);
                       });
      if (add_operand_it == add->operands().end()) {
        return false;
      }
      auto* matched_add_operand = *add_operand_it;
      // Calculate operand index of 'add' operand which was not matched above.
      const int64 other_add_operand_index =
          matched_add_operand == add->operand(0) ? 1 : 0;
      // Returns true iff there is exactly one use of 'operand' at shape index
      // 'operand_index', and this singleton use is the fused root (at operand
      // index 'other_add_operand_index').
      return HasUniqueFusedUseOfOperandAt(operand, operand_index, user,
                                          other_add_operand_index,
                                          *points_to_analysis);
    }
  }
  if (user->opcode() == HloOpcode::kDynamicUpdateSlice ||
      user->opcode() == HloOpcode::kWhile) {
    // We eliminated other users in BufferLiveness::live_range_strictly_before,
    // so here we just need to check that the use is at operand index 0.
    std::vector<int64> operand_indices = user->OperandIndices(operand);
    return operand_indices.size() == 1 && operand_indices[0] == 0;
  }
  // Check if 'user' is element-wise.
  return user->IsElementwise();
}

}  // namespace xla
<commit_msg>Avoid unncessarily creating two new Shape objects in xla::CanShareOperandBufferWithUser.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/liveness_util.h"

#include <algorithm>
#include <utility>
#include <vector>

#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/logical_buffer.h"
#include "tensorflow/compiler/xla/service/tuple_points_to_analysis.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/compiler/xla/types.h"
#include "tensorflow/compiler/xla/util.h"

namespace xla {

bool DoesNotUseOperandBuffer(const HloInstruction* operand,
                             const ShapeIndex& index,
                             const HloInstruction* user,
                             const TuplePointsToAnalysis& points_to_analysis) {
  CHECK(user->IsUserOf(operand))
      << "user: " << user->ToString() << " operand: " << operand->ToString();
  if (user->opcode() == HloOpcode::kGetTupleElement && !index.empty()) {
    // GetTupleElement instructions only access the top-level buffer of their
    // operand.
    return true;
  } else if (user->opcode() == HloOpcode::kFusion &&
             user->fusion_kind() == HloInstruction::FusionKind::kLoop) {
    // Find fusion parameter associated with 'operand'.
    auto it = std::find_if(
        user->fused_parameters().begin(), user->fused_parameters().end(),
        [=](HloInstruction* fused_param) {
          return user->operand(fused_param->parameter_number()) == operand;
        });
    CHECK(it != user->fused_parameters().end());
    // Iterate through all users of all buffer aliases of the buffer in the
    // points-to set of fusion parameter at 'index'.
    // Return false if any uses are detected at 'index', returns true otherwise.
    const LogicalBuffer* buffer =
        points_to_analysis.GetBufferDefinedAt(*it, index).ValueOrDie();
    for (const BufferAlias& alias :
         points_to_analysis.GetBufferAliases(*buffer)) {
      for (HloInstruction* alias_user : alias.instruction()->users()) {
        if (DoesNotUseOperandBuffer(alias.instruction(), alias.index(),
                                    alias_user, points_to_analysis)) {
          continue;
        }
        // Return false: use detected at 'buffer' -> 'alias' -> 'alias_user'.
        return false;
      }
    }
    // Return true: found no uses of 'operand' at 'index' in 'user'.
    return true;
  }
  return false;
}

namespace {

// Returns all uses of all aliases of 'instruction' at 'index' in 'uses'.
// Each use in 'uses' is a pair (HloInstruction* user, int64 operand_index)
// where 'user' is a user of an alias of 'intruction' at 'index', and
// 'operand_index' is the operand index at which the alias appears in the
// operand list of 'user'.
std::vector<std::pair<HloInstruction*, int64>> GetAllUsesOfInstructionAtIndex(
    HloInstruction* instruction, const ShapeIndex& index,
    const TuplePointsToAnalysis& points_to_analysis) {
  std::vector<std::pair<HloInstruction*, int64>> uses;
  const std::vector<const LogicalBuffer*>& points_to =
      points_to_analysis.GetPointsToSet(instruction).element(index);
  for (const LogicalBuffer* buffer : points_to) {
    for (const BufferAlias& alias :
         points_to_analysis.GetBufferAliases(*buffer)) {
      for (HloInstruction* alias_user : alias.instruction()->users()) {
        if (DoesNotUseOperandBuffer(alias.instruction(), alias.index(),
                                    alias_user, points_to_analysis)) {
          continue;
        }
        for (int64 op_idx : alias_user->OperandIndices(alias.instruction())) {
          uses.emplace_back(alias_user, op_idx);
        }
      }
    }
  }
  return uses;
}

// Returns true if there is exactly one use of 'operand' at 'operand_index'
// in 'fusion.fused_instructions', where the singleton use is the fused
// root at operand index 'use_operand_index'. Returns false otherwise.
//
// REQUIRES: 'fusion' opcode is a kFusion instruction.
bool HasUniqueFusedUseOfOperandAt(
    HloInstruction* operand, const ShapeIndex& operand_index,
    HloInstruction* fusion, const int64 use_operand_index,
    const TuplePointsToAnalysis& points_to_analysis) {
  CHECK_EQ(HloOpcode::kFusion, fusion->opcode());
  // Check that 'operand' is unique in the operand list of 'fusion'.
  if (fusion->OperandIndices(operand).size() > 1) {
    return false;
  }
  // Find fusion parameter associated with 'operand'.
  const auto& fused_params = fusion->fused_parameters();
  auto fused_param_it = std::find_if(
      fused_params.begin(), fused_params.end(),
      [&](HloInstruction* fused_param) {
        return fusion->operand(fused_param->parameter_number()) == operand;
      });
  if (fused_param_it == fused_params.end()) {
    return false;
  }
  auto* fused_param = *fused_param_it;
  // Get all uses of 'operand' at 'index' from 'fusion.fused_instructions'.
  auto fused_param_uses = GetAllUsesOfInstructionAtIndex(
      fused_param, operand_index, points_to_analysis);
  // Return true iff there is exactly one use of 'operand' at 'index', and
  // this singleton use is the fused root (at index in 'use_operand_indices').
  return fused_param_uses.size() == 1 &&
         fused_param_uses[0].first == fusion->fused_expression_root() &&
         fused_param_uses[0].second == use_operand_index;
}

}  // namespace

// User and operand can share buffers iff both instructions emit the same shape
// and layout, and 'user' meets one of the following qualifications:
//
// (1) Is element-wise. Or...
// (2) Is a loop fusion instruction where the only use of 'operand' at 'index'
//     in the set 'user.fused_instructions' is a DynamicUpdateSlice fused root
//     at operand 0. Or...
// (3) Is a kDot -> kAdd (or fused kTransposeDot -> kAdd) output fusion
//     instruction where the only use of 'operand' at 'index' in the set
//     'user.fused_instructions' is a kAdd fused root at operand 0 or 1. Or...
// (4) The 'user' of 'operand' is DynamicUpdateSlice or While at operand index
//     0.
//
// (2) and (3) can only be determined if points-to analysis is available.
bool CanShareOperandBufferWithUser(
    HloInstruction* operand, const ShapeIndex& operand_index,
    HloInstruction* user, const ShapeIndex& user_index,
    const TuplePointsToAnalysis* points_to_analysis) {
  CHECK(user->IsUserOf(operand))
      << "user: " << user->ToString() << " operand: " << operand->ToString();
  const Shape& operand_subshape =
      ShapeUtil::GetSubshape(operand->shape(), operand_index);
  const Shape& user_subshape =
      ShapeUtil::GetSubshape(user->shape(), user_index);
  // Check that operand and user emit the same shape and layout.
  if (!ShapeUtil::Equal(operand_subshape, user_subshape)) {
    return false;
  }
  if (points_to_analysis != nullptr && user->opcode() == HloOpcode::kFusion) {
    if (user->fusion_kind() == HloInstruction::FusionKind::kLoop &&
        user->fused_expression_root()->opcode() ==
            HloOpcode::kDynamicUpdateSlice) {
      // Loop fusion with kDynamicUpdateSlice fused root.
      //
      // Returns true iff there is exactly one use of 'operand' at shape index
      // 'operand_index', and this singleton use is the fused root at operand
      // index 0.
      return HasUniqueFusedUseOfOperandAt(operand, operand_index, user, 0,
                                          *points_to_analysis);
    } else if (user->fusion_kind() == HloInstruction::FusionKind::kOutput &&
               user->fused_expression_root()->opcode() == HloOpcode::kAdd) {
      // Output fusion with kAdd fused root.

      // Check if one operand of kAdd fused root is either kDot, or nested
      // kFusion of kind kTransposeDot.
      auto* add = user->fused_expression_root();
      auto add_operand_it =
          std::find_if(add->operands().begin(), add->operands().end(),
                       [&](HloInstruction* operand) {
                         return operand->opcode() == HloOpcode::kDot ||
                                (operand->opcode() == HloOpcode::kFusion &&
                                 operand->fusion_kind() ==
                                     HloInstruction::FusionKind::kTransposeDot);
                       });
      if (add_operand_it == add->operands().end()) {
        return false;
      }
      auto* matched_add_operand = *add_operand_it;
      // Calculate operand index of 'add' operand which was not matched above.
      const int64 other_add_operand_index =
          matched_add_operand == add->operand(0) ? 1 : 0;
      // Returns true iff there is exactly one use of 'operand' at shape index
      // 'operand_index', and this singleton use is the fused root (at operand
      // index 'other_add_operand_index').
      return HasUniqueFusedUseOfOperandAt(operand, operand_index, user,
                                          other_add_operand_index,
                                          *points_to_analysis);
    }
  }
  if (user->opcode() == HloOpcode::kDynamicUpdateSlice ||
      user->opcode() == HloOpcode::kWhile) {
    // We eliminated other users in BufferLiveness::live_range_strictly_before,
    // so here we just need to check that the use is at operand index 0.
    std::vector<int64> operand_indices = user->OperandIndices(operand);
    return operand_indices.size() == 1 && operand_indices[0] == 0;
  }
  // Check if 'user' is element-wise.
  return user->IsElementwise();
}

}  // namespace xla
<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/platform_util.h"

#include <algorithm>
#include <string>
#include <utility>

#include "absl/strings/ascii.h"
#include "absl/strings/str_join.h"
#include "tensorflow/compiler/xla/service/compiler.h"
#include "tensorflow/compiler/xla/status_macros.h"
#include "tensorflow/compiler/xla/statusor.h"
#include "tensorflow/compiler/xla/types.h"
#include "tensorflow/compiler/xla/util.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/stream_executor_no_cuda.h"

namespace xla {

// Minimum supported CUDA compute capability is 3.5.
constexpr int kMinCudaComputeCapabilityMajor = 3;
constexpr int kMinCudaComputeCapabilityMinor = 5;

// The name of the interpreter platform.
constexpr char kInterpreter[] = "interpreter";

namespace {

string CanonicalPlatformName(const string& name) {
  string platform_str = absl::AsciiStrToLower(name);
  // "cpu" and "host" mean the same thing.
  if (platform_str == "cpu") {
    platform_str = "host";
  }
  // "gpu" and "cuda" mean the same thing.
  if (platform_str == "gpu") {
    platform_str = "cuda";
  }
  return platform_str;
}

}  // namespace

/* static */ StatusOr<std::vector<se::Platform*>>
PlatformUtil::GetSupportedPlatforms() {
  se::MultiPlatformManager::PlatformMap platform_map;
  se::port::Status platforms_status = se::MultiPlatformManager::WithPlatforms(
      [&platform_map](se::MultiPlatformManager::PlatformMap* map) {
        platform_map = *map;
        return se::port::Status::OK();
      });
  if (platform_map.empty()) {
    LOG(WARNING) << "no executor platforms available: platform map is empty";
  }

  // Gather all platforms which have an XLA compiler.
  std::vector<se::Platform*> platforms;
  for (auto& platform_pair : platform_map) {
    auto* platform = platform_pair.second;
    auto compiler_status = Compiler::GetForPlatform(platform);
    if (compiler_status.ok()) {
      platforms.push_back(platform);
    } else {
      LOG(INFO) << "platform " << platform->Name() << " present but no "
                << "XLA compiler available: "
                << compiler_status.status().error_message();
    }
  }
  return platforms;
}

/* static */ StatusOr<se::Platform*> PlatformUtil::GetSolePlatform() {
  TF_ASSIGN_OR_RETURN(auto platforms, GetSupportedPlatforms());
  if (platforms.empty()) {
    return NotFound("no platforms found");
  } else if (platforms.size() == 1) {
    return platforms[0];
  }

  // Multiple platforms present and we can't pick a reasonable default.
  string platforms_string = absl::StrJoin(
      platforms, ", ",
      [](string* out, const se::Platform* p) { out->append(p->Name()); });
  return InvalidArgument(
      "must specify platform because more than one platform found: %s",
      platforms_string);
}

/* static */ StatusOr<se::Platform*> PlatformUtil::GetDefaultPlatform() {
  TF_ASSIGN_OR_RETURN(auto platforms, GetSupportedPlatforms());
  if (platforms.empty()) {
    return NotFound("no platforms found");
  } else if (platforms.size() == 1) {
    return platforms[0];
  } else if (platforms.size() == 2) {
    for (int i = 0; i < 2; i++) {
      if (absl::AsciiStrToLower(platforms[i]->Name()) == kInterpreter &&
          absl::AsciiStrToLower(platforms[1 - i]->Name()) != kInterpreter) {
        return platforms[1 - i];
      }
    }
  }

  // Multiple platforms present and we can't pick a reasonable default.
  string platforms_string = absl::StrJoin(
      platforms, ", ",
      [](string* out, const se::Platform* p) { out->append(p->Name()); });
  return InvalidArgument(
      "must specify platform because more than one platform (except for the "
      "interpreter platform) found: %s",
      platforms_string);
}

/*static*/ StatusOr<se::Platform*> PlatformUtil::GetPlatform(
    const string& platform_name) {
  string platform_str = CanonicalPlatformName(platform_name);
  TF_ASSIGN_OR_RETURN(auto platforms, PlatformUtil::GetSupportedPlatforms());
  for (se::Platform* platform : platforms) {
    if (absl::AsciiStrToLower(platform->Name()) == platform_str) {
      return platform;
    }
  }
  return InvalidArgument("platform %s not found", platform_name);
}

/*static*/ StatusOr<se::Platform*> PlatformUtil::GetPlatformExceptFor(
    const string& platform_name) {
  string platform_str = CanonicalPlatformName(platform_name);

  TF_ASSIGN_OR_RETURN(auto platforms, PlatformUtil::GetSupportedPlatforms());
  std::vector<se::Platform*> matched;
  for (se::Platform* platform : platforms) {
    if (absl::AsciiStrToLower(platform->Name()) != platform_name) {
      matched.push_back(platform);
    }
  }
  if (matched.empty()) {
    return InvalidArgument("unable to find platform that is not %s",
                           platform_name);
  }
  if (matched.size() == 1) {
    return matched[0];
  }
  string matched_string = absl::StrJoin(
      matched, ", ",
      [](string* out, const se::Platform* p) { out->append(p->Name()); });
  return InvalidArgument(
      "found multiple platforms %s, but expected one platform except for %s",
      matched_string, platform_name);
}

// Returns whether the device underlying the given StreamExecutor is supported
// by XLA.
static bool IsDeviceSupported(se::StreamExecutor* executor) {
  const auto& description = executor->GetDeviceDescription();
  if (executor->platform()->id() == se::cuda::kCudaPlatformId) {
    // CUDA devices must have a minimum compute capability.
    int major_version, minor_version;
    if (description.cuda_compute_capability(&major_version, &minor_version)) {
      if (major_version < kMinCudaComputeCapabilityMajor ||
          (major_version == kMinCudaComputeCapabilityMajor &&
           minor_version < kMinCudaComputeCapabilityMinor)) {
        LOG(INFO) << "StreamExecutor cuda device ("
                  << executor->device_ordinal() << ") is of "
                  << "insufficient compute capability: "
                  << kMinCudaComputeCapabilityMajor << "."
                  << kMinCudaComputeCapabilityMinor << " required, "
                  << "device is " << major_version << "." << minor_version;
        return false;
      }
    }
  }
  return true;
}

/* static */ StatusOr<std::vector<se::StreamExecutor*>>
PlatformUtil::GetStreamExecutors(se::Platform* platform) {
  int device_count = platform->VisibleDeviceCount();
  if (device_count <= 0) {
    return NotFound("no %s devices found", platform->Name());
  }
  if (platform->id() == se::host::kHostPlatformId) {
    // On host "devices", StreamExecutor exports a device for each hardware
    // thread. Because we parallelize a single computation across threads, it
    // doesn't make sense to expose these as separate devices, so fix the number
    // of devices to one.
    device_count = 1;
  }
  std::vector<se::StreamExecutor*> stream_executors(device_count, nullptr);
  VLOG(1) << "Initializing devices";
  {
    tensorflow::thread::ThreadPool thread_pool(
        tensorflow::Env::Default(), "device_initialization", device_count);
    for (int i = 0; i < device_count; ++i) {
      thread_pool.Schedule([platform, i, &stream_executors]() {
        VLOG(1) << "Started device init " << i;
        se::StreamExecutorConfig config;
        config.ordinal = i;
        auto executor_status = platform->GetExecutor(config);
        if (executor_status.ok()) {
          se::StreamExecutor* executor = executor_status.ValueOrDie();
          if (IsDeviceSupported(executor)) {
            stream_executors[i] = executor;
          }
        } else {
          LOG(WARNING) << "unable to create StreamExecutor for "
                       << platform->Name() << ":" << i << ": "
                       << executor_status.status().error_message();
        }
        VLOG(1) << "Finished device init " << i;
      });
    }
    // Block here in thread_pool destructor until all devices are initialized.
  }
  VLOG(1) << "Device initialization complete";
  if (std::all_of(stream_executors.begin(), stream_executors.end(),
                  [](se::StreamExecutor* s) { return s == nullptr; })) {
    return InternalError("no supported devices found for platform %s",
                         platform->Name());
  }
  return stream_executors;
}

}  // namespace xla
<commit_msg>Make sure the platform is initialized before use.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/platform_util.h"

#include <algorithm>
#include <string>
#include <utility>

#include "absl/strings/ascii.h"
#include "absl/strings/str_join.h"
#include "tensorflow/compiler/xla/service/compiler.h"
#include "tensorflow/compiler/xla/status_macros.h"
#include "tensorflow/compiler/xla/statusor.h"
#include "tensorflow/compiler/xla/types.h"
#include "tensorflow/compiler/xla/util.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/stream_executor_no_cuda.h"

namespace xla {

// Minimum supported CUDA compute capability is 3.5.
constexpr int kMinCudaComputeCapabilityMajor = 3;
constexpr int kMinCudaComputeCapabilityMinor = 5;

// The name of the interpreter platform.
constexpr char kInterpreter[] = "interpreter";

namespace {

string CanonicalPlatformName(const string& name) {
  string platform_str = absl::AsciiStrToLower(name);
  // "cpu" and "host" mean the same thing.
  if (platform_str == "cpu") {
    platform_str = "host";
  }
  // "gpu" and "cuda" mean the same thing.
  if (platform_str == "gpu") {
    platform_str = "cuda";
  }
  return platform_str;
}

}  // namespace

/* static */ StatusOr<std::vector<se::Platform*>>
PlatformUtil::GetSupportedPlatforms() {
  se::MultiPlatformManager::PlatformMap platform_map;
  se::port::Status platforms_status = se::MultiPlatformManager::WithPlatforms(
      [&platform_map](se::MultiPlatformManager::PlatformMap* map) {
        platform_map = *map;
        return se::port::Status::OK();
      });
  if (platform_map.empty()) {
    LOG(WARNING) << "no executor platforms available: platform map is empty";
  }

  // Gather all platforms which have an XLA compiler.
  std::vector<se::Platform*> platforms;
  for (auto& platform_pair : platform_map) {
    auto* platform = platform_pair.second;
    auto compiler_status = Compiler::GetForPlatform(platform);
    if (compiler_status.ok()) {
      platforms.push_back(platform);
    } else {
      LOG(INFO) << "platform " << platform->Name() << " present but no "
                << "XLA compiler available: "
                << compiler_status.status().error_message();
    }
  }
  return platforms;
}

/* static */ StatusOr<se::Platform*> PlatformUtil::GetSolePlatform() {
  TF_ASSIGN_OR_RETURN(auto platforms, GetSupportedPlatforms());
  if (platforms.empty()) {
    return NotFound("no platforms found");
  } else if (platforms.size() == 1) {
    se::Platform* platform = platforms[0];
    if (!platform->Initialized()) {
      TF_RETURN_IF_ERROR(platform->Initialize({}));
    }
    return platform;
  }

  // Multiple platforms present and we can't pick a reasonable default.
  string platforms_string = absl::StrJoin(
      platforms, ", ",
      [](string* out, const se::Platform* p) { out->append(p->Name()); });
  return InvalidArgument(
      "must specify platform because more than one platform found: %s",
      platforms_string);
}

/* static */ StatusOr<se::Platform*> PlatformUtil::GetDefaultPlatform() {
  TF_ASSIGN_OR_RETURN(auto platforms, GetSupportedPlatforms());

  se::Platform* platform = nullptr;
  if (platforms.empty()) {
    return NotFound("no platforms found");
  } else if (platforms.size() == 1) {
    platform = platforms[0];
  } else if (platforms.size() == 2) {
    for (int i = 0; i < 2; i++) {
      if (absl::AsciiStrToLower(platforms[i]->Name()) == kInterpreter &&
          absl::AsciiStrToLower(platforms[1 - i]->Name()) != kInterpreter) {
        platform = platforms[1 - i];
        break;
      }
    }
  }
  if (platform != nullptr) {
    if (!platform->Initialized()) {
      TF_RETURN_IF_ERROR(platform->Initialize({}));
    }
    return platform;
  }

  // Multiple platforms present and we can't pick a reasonable default.
  string platforms_string = absl::StrJoin(
      platforms, ", ",
      [](string* out, const se::Platform* p) { out->append(p->Name()); });
  return InvalidArgument(
      "must specify platform because more than one platform (except for the "
      "interpreter platform) found: %s",
      platforms_string);
}

/*static*/ StatusOr<se::Platform*> PlatformUtil::GetPlatform(
    const string& platform_name) {
  string platform_str = CanonicalPlatformName(platform_name);
  TF_ASSIGN_OR_RETURN(auto platforms, PlatformUtil::GetSupportedPlatforms());
  for (se::Platform* platform : platforms) {
    if (absl::AsciiStrToLower(platform->Name()) == platform_str) {
      if (!platform->Initialized()) {
        TF_RETURN_IF_ERROR(platform->Initialize({}));
      }
      return platform;
    }
  }
  return InvalidArgument("platform %s not found", platform_name);
}

/*static*/ StatusOr<se::Platform*> PlatformUtil::GetPlatformExceptFor(
    const string& platform_name) {
  string platform_str = CanonicalPlatformName(platform_name);

  TF_ASSIGN_OR_RETURN(auto platforms, PlatformUtil::GetSupportedPlatforms());
  std::vector<se::Platform*> matched;
  for (se::Platform* platform : platforms) {
    if (absl::AsciiStrToLower(platform->Name()) != platform_name) {
      matched.push_back(platform);
    }
  }
  if (matched.empty()) {
    return InvalidArgument("unable to find platform that is not %s",
                           platform_name);
  }
  if (matched.size() == 1) {
    auto platform = matched[0];
    if (!platform->Initialized()) {
      TF_RETURN_IF_ERROR(platform->Initialize({}));
    }
    return platform;
  }
  string matched_string = absl::StrJoin(
      matched, ", ",
      [](string* out, const se::Platform* p) { out->append(p->Name()); });
  return InvalidArgument(
      "found multiple platforms %s, but expected one platform except for %s",
      matched_string, platform_name);
}

// Returns whether the device underlying the given StreamExecutor is supported
// by XLA.
static bool IsDeviceSupported(se::StreamExecutor* executor) {
  const auto& description = executor->GetDeviceDescription();
  if (executor->platform()->id() == se::cuda::kCudaPlatformId) {
    // CUDA devices must have a minimum compute capability.
    int major_version, minor_version;
    if (description.cuda_compute_capability(&major_version, &minor_version)) {
      if (major_version < kMinCudaComputeCapabilityMajor ||
          (major_version == kMinCudaComputeCapabilityMajor &&
           minor_version < kMinCudaComputeCapabilityMinor)) {
        LOG(INFO) << "StreamExecutor cuda device ("
                  << executor->device_ordinal() << ") is of "
                  << "insufficient compute capability: "
                  << kMinCudaComputeCapabilityMajor << "."
                  << kMinCudaComputeCapabilityMinor << " required, "
                  << "device is " << major_version << "." << minor_version;
        return false;
      }
    }
  }
  return true;
}

/* static */ StatusOr<std::vector<se::StreamExecutor*>>
PlatformUtil::GetStreamExecutors(se::Platform* platform) {
  int device_count = platform->VisibleDeviceCount();
  if (device_count <= 0) {
    return NotFound("no %s devices found", platform->Name());
  }
  if (platform->id() == se::host::kHostPlatformId) {
    // On host "devices", StreamExecutor exports a device for each hardware
    // thread. Because we parallelize a single computation across threads, it
    // doesn't make sense to expose these as separate devices, so fix the number
    // of devices to one.
    device_count = 1;
  }
  std::vector<se::StreamExecutor*> stream_executors(device_count, nullptr);
  VLOG(1) << "Initializing devices";
  {
    tensorflow::thread::ThreadPool thread_pool(
        tensorflow::Env::Default(), "device_initialization", device_count);
    for (int i = 0; i < device_count; ++i) {
      thread_pool.Schedule([platform, i, &stream_executors]() {
        VLOG(1) << "Started device init " << i;
        se::StreamExecutorConfig config;
        config.ordinal = i;
        auto executor_status = platform->GetExecutor(config);
        if (executor_status.ok()) {
          se::StreamExecutor* executor = executor_status.ValueOrDie();
          if (IsDeviceSupported(executor)) {
            stream_executors[i] = executor;
          }
        } else {
          LOG(WARNING) << "unable to create StreamExecutor for "
                       << platform->Name() << ":" << i << ": "
                       << executor_status.status().error_message();
        }
        VLOG(1) << "Finished device init " << i;
      });
    }
    // Block here in thread_pool destructor until all devices are initialized.
  }
  VLOG(1) << "Device initialization complete";
  if (std::all_of(stream_executors.begin(), stream_executors.end(),
                  [](se::StreamExecutor* s) { return s == nullptr; })) {
    return InternalError("no supported devices found for platform %s",
                         platform->Name());
  }
  return stream_executors;
}

}  // namespace xla
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/util/gzip_utils.h"

// For bazel build.
#include "perfetto/base/build_config.h"
#include "perfetto/base/compiler.h"

#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
#include <zlib.h>
#else
struct z_stream_s {};
#endif

namespace perfetto {
namespace trace_processor {
namespace util {

bool IsGzipSupported() {
#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
  return true;
#else
  return false;
#endif
}

#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)  // Real Implementation

GzipDecompressor::GzipDecompressor() : z_stream_(new z_stream()) {
  z_stream_->zalloc = nullptr;
  z_stream_->zfree = nullptr;
  z_stream_->opaque = nullptr;
  inflateInit2(z_stream_.get(), 32 + MAX_WBITS);
}

GzipDecompressor::~GzipDecompressor() {
  inflateEnd(z_stream_.get());
}

void GzipDecompressor::Reset() {
  inflateReset(z_stream_.get());
}

void GzipDecompressor::Feed(const uint8_t* data, size_t size) {
  // This const_cast is not harmfull as zlib will not modify the data in this
  // pointer. This is only necessary because of the build flags we use to be
  // compatible with other embedders.
  z_stream_->next_in = const_cast<uint8_t*>(data);
  z_stream_->avail_in = static_cast<uInt>(size);
}

GzipDecompressor::Result GzipDecompressor::ExtractOutput(uint8_t* out,
                                                         size_t out_size) {
  if (z_stream_->avail_in == 0)
    return Result{ResultCode::kNeedsMoreInput, 0};

  z_stream_->next_out = out;
  z_stream_->avail_out = static_cast<uInt>(out_size);

  int ret = inflate(z_stream_.get(), Z_NO_FLUSH);
  switch (ret) {
    case Z_NEED_DICT:
    case Z_DATA_ERROR:
    case Z_MEM_ERROR:
      // Ignore inflateEnd error as we will error out anyway.
      inflateEnd(z_stream_.get());
      return Result{ResultCode::kError, 0};
    case Z_STREAM_END:
      return Result{ResultCode::kEof, out_size - z_stream_->avail_out};
    case Z_BUF_ERROR:
      return Result{ResultCode::kNeedsMoreInput, 0};
    default:
      return Result{ResultCode::kOk, out_size - z_stream_->avail_out};
  }
}

#else  // Dummy Implementation

GzipDecompressor::GzipDecompressor() = default;
GzipDecompressor::~GzipDecompressor() = default;
void GzipDecompressor::Reset() {}
void GzipDecompressor::Feed(const uint8_t*, size_t) {}
GzipDecompressor::Result GzipDecompressor::ExtractOutput(uint8_t*, size_t) {
  Result{ResultCode::kError, 0};
}

#endif  // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)

// static
std::vector<uint8_t> GzipDecompressor::DecompressFully(const uint8_t* data,
                                                       size_t len) {
  std::vector<uint8_t> whole_data;
  GzipDecompressor decompressor;
  auto decom_output_consumer = [&](const uint8_t* buf, size_t buf_len) {
    whole_data.insert(whole_data.end(), buf, buf + buf_len);
  };
  decompressor.FeedAndExtract(data, len, decom_output_consumer);
  return whole_data;
}

}  // namespace util
}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>Fix chrome rollback due to missign return am: ed5834c3fe am: 15e4c595c7<commit_after>/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/util/gzip_utils.h"

// For bazel build.
#include "perfetto/base/build_config.h"
#include "perfetto/base/compiler.h"

#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
#include <zlib.h>
#else
struct z_stream_s {};
#endif

namespace perfetto {
namespace trace_processor {
namespace util {

bool IsGzipSupported() {
#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
  return true;
#else
  return false;
#endif
}

#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)  // Real Implementation

GzipDecompressor::GzipDecompressor() : z_stream_(new z_stream()) {
  z_stream_->zalloc = nullptr;
  z_stream_->zfree = nullptr;
  z_stream_->opaque = nullptr;
  inflateInit2(z_stream_.get(), 32 + MAX_WBITS);
}

GzipDecompressor::~GzipDecompressor() {
  inflateEnd(z_stream_.get());
}

void GzipDecompressor::Reset() {
  inflateReset(z_stream_.get());
}

void GzipDecompressor::Feed(const uint8_t* data, size_t size) {
  // This const_cast is not harmfull as zlib will not modify the data in this
  // pointer. This is only necessary because of the build flags we use to be
  // compatible with other embedders.
  z_stream_->next_in = const_cast<uint8_t*>(data);
  z_stream_->avail_in = static_cast<uInt>(size);
}

GzipDecompressor::Result GzipDecompressor::ExtractOutput(uint8_t* out,
                                                         size_t out_size) {
  if (z_stream_->avail_in == 0)
    return Result{ResultCode::kNeedsMoreInput, 0};

  z_stream_->next_out = out;
  z_stream_->avail_out = static_cast<uInt>(out_size);

  int ret = inflate(z_stream_.get(), Z_NO_FLUSH);
  switch (ret) {
    case Z_NEED_DICT:
    case Z_DATA_ERROR:
    case Z_MEM_ERROR:
      // Ignore inflateEnd error as we will error out anyway.
      inflateEnd(z_stream_.get());
      return Result{ResultCode::kError, 0};
    case Z_STREAM_END:
      return Result{ResultCode::kEof, out_size - z_stream_->avail_out};
    case Z_BUF_ERROR:
      return Result{ResultCode::kNeedsMoreInput, 0};
    default:
      return Result{ResultCode::kOk, out_size - z_stream_->avail_out};
  }
}

#else  // Dummy Implementation

GzipDecompressor::GzipDecompressor() = default;
GzipDecompressor::~GzipDecompressor() = default;
void GzipDecompressor::Reset() {}
void GzipDecompressor::Feed(const uint8_t*, size_t) {}
GzipDecompressor::Result GzipDecompressor::ExtractOutput(uint8_t*, size_t) {
  return Result{ResultCode::kError, 0};
}

#endif  // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)

// static
std::vector<uint8_t> GzipDecompressor::DecompressFully(const uint8_t* data,
                                                       size_t len) {
  std::vector<uint8_t> whole_data;
  GzipDecompressor decompressor;
  auto decom_output_consumer = [&](const uint8_t* buf, size_t buf_len) {
    whole_data.insert(whole_data.end(), buf, buf + buf_len);
  };
  decompressor.FeedAndExtract(data, len, decom_output_consumer);
  return whole_data;
}

}  // namespace util
}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>