<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc
 *
 *   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 "config.h"
#include <sys/types.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <platform/platform.h>
#include "topkeys.h"

static topkey_item_t *topkey_item_init(const void *key, int nkey, rel_time_t ct) {
    topkey_item_t *it = (topkey_item_t *)calloc(sizeof(topkey_item_t) + nkey, 1);
    cb_assert(it);
    cb_assert(key);
    cb_assert(nkey > 0);
    it->ti_nkey = nkey;
    it->ti_ctime = ct;
    it->ti_atime = ct;
    /* Copy the key into the part trailing the struct */
    memcpy(it + 1, key, nkey);
    return it;
}

TopKeys::TopKeys(int mkeys)
    : nkeys(0), max_keys(mkeys)
{
    list.next = &list;
    list.prev = &list;
}

TopKeys::~TopKeys() {
    dlist_t *p = list.next;
    while (p != &list) {
        dlist_t *tmp = p->next;
        free(p);
        p = tmp;
    }
}

static void dlist_remove(dlist_t *list) {
    cb_assert(list->prev->next == list);
    cb_assert(list->next->prev == list);
    list->prev->next = list->next;
    list->next->prev = list->prev;
}

static void dlist_insert_after(dlist_t *list, dlist_t *newitem) {
    newitem->next = list->next;
    newitem->prev = list;
    list->next->prev = newitem;
    list->next = newitem;
}

static void dlist_iter(dlist_t *list,
                       void (*iterfunc)(dlist_t *item, void *arg),
                       void *arg)
{
    dlist_t *p = list;
    while ((p = p->next) != list) {
        iterfunc(p, arg);
    }
}

void TopKeys::deleteTail() {
    topkey_item_t *it = (topkey_item_t*)(list.prev);
    std::string key(reinterpret_cast<char*>(it+1), it->ti_nkey);
    auto iterator = hash.find(key);
    cb_assert(iterator != hash.end());
    hash.erase(iterator);
    dlist_remove(&it->ti_list);
    --nkeys;
    free(it);
}

topkey_item_t *TopKeys::getOrCreate(const void *key, size_t nkey, const rel_time_t ct) {
    try {
        std::string k(reinterpret_cast<const char*>(key), nkey);
        auto iterator = hash.find(k);
        topkey_item_t *it = nullptr;

        if (iterator == hash.end()) {
            it = topkey_item_init(key, (int)nkey, ct);
            if (it != NULL) {
                if (++nkeys > max_keys) {
                    deleteTail();
                }
                hash[k] = it;
            } else {
                return NULL;
            }
        } else {
            it = iterator->second;
            dlist_remove(&it->ti_list);
        }
        dlist_insert_after(&list, &it->ti_list);
        return it;
    } catch (const std::bad_alloc&) {
        return nullptr;
    }
}

void TopKeys::updateKey(const void *key, size_t nkey,
                      rel_time_t operation_time) {
    cb_assert(key);
    cb_assert(nkey > 0);
    std::lock_guard<std::mutex> lock(mutex);
    topkey_item_t *tmp = getOrCreate(key, nkey, operation_time);
    if (tmp != NULL) {
        tmp->ti_access_count++;
    }
}

struct tk_context {
    tk_context(const void *c, ADD_STAT a, rel_time_t t, cJSON *arr)
        : cookie(c), add_stat(a), current_time(t), array(arr)
    {
        // empty
    }

    const void *cookie;
    ADD_STAT add_stat;
    rel_time_t current_time;
    cJSON *array;
};

static void tk_iterfunc(dlist_t *list, void *arg) {
    struct tk_context *c = (struct tk_context*)arg;
    topkey_item_t *it = (topkey_item_t*)list;
    char val_str[500];
    int vlen = snprintf(val_str, sizeof(val_str) - 1, "get_hits=%d,"
                        "get_misses=0,cmd_set=0,incr_hits=0,incr_misses=0,"
                        "decr_hits=0,decr_misses=0,delete_hits=0,"
                        "delete_misses=0,evictions=0,cas_hits=0,cas_badval=0,"
                        "cas_misses=0,get_replica=0,evict=0,getl=0,unlock=0,"
                        "get_meta=0,set_meta=0,del_meta=0,ctime=%" PRIu32
                        ",atime=%" PRIu32, it->ti_access_count,
                        c->current_time - it->ti_ctime,
                        c->current_time - it->ti_atime);
    c->add_stat((char*)(it + 1), it->ti_nkey, val_str, vlen, c->cookie);
}

/**
 * Passing in a list of keys, context, and cJSON array will populate that
 * array with an object for each key in the following format:
 * {
 *    "key": "somekey",
 *    "access_count": nnn,
 *    "ctime": ccc,
 *    "atime": aaa
 * }
 */
static void tk_jsonfunc(dlist_t *list, void *arg) {
    struct tk_context *c = (struct tk_context*)arg;
    topkey_item_t *it = (topkey_item_t*)list;
    cb_assert(it != NULL);
    cJSON *key = cJSON_CreateObject();
    cJSON_AddItemToObject(key, "key", cJSON_CreateString((char *)(it + 1)));
    cJSON_AddItemToObject(key, "access_count",
                          cJSON_CreateNumber(it->ti_access_count));
    cJSON_AddItemToObject(key, "ctime", cJSON_CreateNumber(c->current_time
                                                           - it->ti_ctime));
    cJSON_AddItemToObject(key, "atime", cJSON_CreateNumber(c->current_time
                                                           - it->ti_atime));
    cb_assert(c->array != NULL);
    cJSON_AddItemToArray(c->array, key);
}

ENGINE_ERROR_CODE TopKeys::stats(const void *cookie,
                                 const rel_time_t current_time,
                                 ADD_STAT add_stat) {
    struct tk_context context(cookie, add_stat, current_time, nullptr);

    std::lock_guard<std::mutex> lock(mutex);
    dlist_iter(&list, tk_iterfunc, &context);

    return ENGINE_SUCCESS;
}

/**
 * Passing a set of topkeys, and relevant context data will
 * return a cJSON object containing an array of topkeys (with each key
 * appearing as in the example above for tk_jsonfunc):
 * {
 *   "topkeys": [
 *      { ... }, ..., { ... }
 *    ]
 * }
 */
ENGINE_ERROR_CODE TopKeys::json_stats(cJSON *object,
                                     const rel_time_t current_time) {

    cJSON *topkeys = cJSON_CreateArray();
    struct tk_context context(nullptr, nullptr, current_time, topkeys);

    /* Collate the topkeys JSON object */
    {
        std::lock_guard<std::mutex> lock(mutex);
        dlist_iter(&list, tk_jsonfunc, &context);
    }

    cJSON_AddItemToObject(object, "topkeys", topkeys);
    return ENGINE_SUCCESS;
}
<commit_msg>MB-15780: Fix use of non-NUL terminated string in JSON topkeys<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc
 *
 *   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 "config.h"
#include <sys/types.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <platform/platform.h>
#include "topkeys.h"

static topkey_item_t *topkey_item_init(const void *key, int nkey, rel_time_t ct) {
    topkey_item_t *it = (topkey_item_t *)calloc(sizeof(topkey_item_t) + nkey, 1);
    cb_assert(it);
    cb_assert(key);
    cb_assert(nkey > 0);
    it->ti_nkey = nkey;
    it->ti_ctime = ct;
    it->ti_atime = ct;
    /* Copy the key into the part trailing the struct */
    memcpy(it + 1, key, nkey);
    return it;
}

TopKeys::TopKeys(int mkeys)
    : nkeys(0), max_keys(mkeys)
{
    list.next = &list;
    list.prev = &list;
}

TopKeys::~TopKeys() {
    dlist_t *p = list.next;
    while (p != &list) {
        dlist_t *tmp = p->next;
        free(p);
        p = tmp;
    }
}

static void dlist_remove(dlist_t *list) {
    cb_assert(list->prev->next == list);
    cb_assert(list->next->prev == list);
    list->prev->next = list->next;
    list->next->prev = list->prev;
}

static void dlist_insert_after(dlist_t *list, dlist_t *newitem) {
    newitem->next = list->next;
    newitem->prev = list;
    list->next->prev = newitem;
    list->next = newitem;
}

static void dlist_iter(dlist_t *list,
                       void (*iterfunc)(dlist_t *item, void *arg),
                       void *arg)
{
    dlist_t *p = list;
    while ((p = p->next) != list) {
        iterfunc(p, arg);
    }
}

void TopKeys::deleteTail() {
    topkey_item_t *it = (topkey_item_t*)(list.prev);
    std::string key(reinterpret_cast<char*>(it+1), it->ti_nkey);
    auto iterator = hash.find(key);
    cb_assert(iterator != hash.end());
    hash.erase(iterator);
    dlist_remove(&it->ti_list);
    --nkeys;
    free(it);
}

topkey_item_t *TopKeys::getOrCreate(const void *key, size_t nkey, const rel_time_t ct) {
    try {
        std::string k(reinterpret_cast<const char*>(key), nkey);
        auto iterator = hash.find(k);
        topkey_item_t *it = nullptr;

        if (iterator == hash.end()) {
            it = topkey_item_init(key, (int)nkey, ct);
            if (it != NULL) {
                if (++nkeys > max_keys) {
                    deleteTail();
                }
                hash[k] = it;
            } else {
                return NULL;
            }
        } else {
            it = iterator->second;
            dlist_remove(&it->ti_list);
        }
        dlist_insert_after(&list, &it->ti_list);
        return it;
    } catch (const std::bad_alloc&) {
        return nullptr;
    }
}

void TopKeys::updateKey(const void *key, size_t nkey,
                      rel_time_t operation_time) {
    cb_assert(key);
    cb_assert(nkey > 0);
    std::lock_guard<std::mutex> lock(mutex);
    topkey_item_t *tmp = getOrCreate(key, nkey, operation_time);
    if (tmp != NULL) {
        tmp->ti_access_count++;
    }
}

struct tk_context {
    tk_context(const void *c, ADD_STAT a, rel_time_t t, cJSON *arr)
        : cookie(c), add_stat(a), current_time(t), array(arr)
    {
        // empty
    }

    const void *cookie;
    ADD_STAT add_stat;
    rel_time_t current_time;
    cJSON *array;
};

static void tk_iterfunc(dlist_t *list, void *arg) {
    struct tk_context *c = (struct tk_context*)arg;
    topkey_item_t *it = (topkey_item_t*)list;
    char val_str[500];
    int vlen = snprintf(val_str, sizeof(val_str) - 1, "get_hits=%d,"
                        "get_misses=0,cmd_set=0,incr_hits=0,incr_misses=0,"
                        "decr_hits=0,decr_misses=0,delete_hits=0,"
                        "delete_misses=0,evictions=0,cas_hits=0,cas_badval=0,"
                        "cas_misses=0,get_replica=0,evict=0,getl=0,unlock=0,"
                        "get_meta=0,set_meta=0,del_meta=0,ctime=%" PRIu32
                        ",atime=%" PRIu32, it->ti_access_count,
                        c->current_time - it->ti_ctime,
                        c->current_time - it->ti_atime);
    c->add_stat((char*)(it + 1), it->ti_nkey, val_str, vlen, c->cookie);
}

/**
 * Passing in a list of keys, context, and cJSON array will populate that
 * array with an object for each key in the following format:
 * {
 *    "key": "somekey",
 *    "access_count": nnn,
 *    "ctime": ccc,
 *    "atime": aaa
 * }
 */
static void tk_jsonfunc(dlist_t *list, void *arg) {
    struct tk_context *c = (struct tk_context*)arg;
    topkey_item_t *it = (topkey_item_t*)list;
    cb_assert(it != NULL);
    cJSON *key = cJSON_CreateObject();
    std::string key_name((char *)(it + 1), it->ti_nkey);
    cJSON_AddItemToObject(key, "key", cJSON_CreateString(key_name.c_str()));
    cJSON_AddItemToObject(key, "access_count",
                          cJSON_CreateNumber(it->ti_access_count));
    cJSON_AddItemToObject(key, "ctime", cJSON_CreateNumber(c->current_time
                                                           - it->ti_ctime));
    cJSON_AddItemToObject(key, "atime", cJSON_CreateNumber(c->current_time
                                                           - it->ti_atime));
    cb_assert(c->array != NULL);
    cJSON_AddItemToArray(c->array, key);
}

ENGINE_ERROR_CODE TopKeys::stats(const void *cookie,
                                 const rel_time_t current_time,
                                 ADD_STAT add_stat) {
    struct tk_context context(cookie, add_stat, current_time, nullptr);

    std::lock_guard<std::mutex> lock(mutex);
    dlist_iter(&list, tk_iterfunc, &context);

    return ENGINE_SUCCESS;
}

/**
 * Passing a set of topkeys, and relevant context data will
 * return a cJSON object containing an array of topkeys (with each key
 * appearing as in the example above for tk_jsonfunc):
 * {
 *   "topkeys": [
 *      { ... }, ..., { ... }
 *    ]
 * }
 */
ENGINE_ERROR_CODE TopKeys::json_stats(cJSON *object,
                                     const rel_time_t current_time) {

    cJSON *topkeys = cJSON_CreateArray();
    struct tk_context context(nullptr, nullptr, current_time, topkeys);

    /* Collate the topkeys JSON object */
    {
        std::lock_guard<std::mutex> lock(mutex);
        dlist_iter(&list, tk_jsonfunc, &context);
    }

    cJSON_AddItemToObject(object, "topkeys", topkeys);
    return ENGINE_SUCCESS;
}
<|endoftext|>


<commit_before>/*********************************************************************
 *
 * Copyright 2011 Intel Corporation
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *********************************************************************/

#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#include <iostream>

#include "os_string.hpp"
#include "os_process.hpp"

#include "cli.hpp"
#include "cli_resources.hpp"

#if defined(__APPLE__)
#define TRACE_VARIABLE "DYLD_LIBRARY_PATH"
#define GL_TRACE_WRAPPER  "OpenGL"
#elif defined(_WIN32)
#define GL_TRACE_WRAPPER  "opengl32.dll"
#else
#define TRACE_VARIABLE "LD_PRELOAD"
#define GL_TRACE_WRAPPER  "glxtrace.so"
#define EGL_TRACE_WRAPPER  "egltrace.so"
#endif

static inline bool
copyWrapper(const os::String & wrapperPath,
            const char *programPath,
            bool verbose)
{
    os::String wrapperFilename(wrapperPath);
    wrapperFilename.trimDirectory();

    os::String tmpWrapper(programPath);
    tmpWrapper.trimFilename();
    tmpWrapper.join(wrapperFilename);

    if (verbose) {
        std::cerr << wrapperPath << " -> " << tmpWrapper << "\n";
    }

    if (tmpWrapper.exists()) {
        std::cerr << "error: not overwriting " << tmpWrapper << "\n";
        return false;
    }

    if (!os::copyFile(wrapperPath, tmpWrapper, false)) {
        std::cerr << "error: failed to copy " << wrapperPath << " into " << tmpWrapper << "\n";
        return false;
    }

    return true;
}

static int
traceProgram(trace::API api,
             char * const *argv,
             const char *output,
             bool verbose)
{
    const char *wrapperFilename;
    std::vector<const char *> args;
    int status = 1;

    /*
     * TODO: simplify code
     */

    bool useInject = false;
    switch (api) {
    case trace::API_GL:
        wrapperFilename = GL_TRACE_WRAPPER;
        break;
#ifdef EGL_TRACE_WRAPPER
    case trace::API_EGL:
        wrapperFilename = EGL_TRACE_WRAPPER;
        break;
#endif
#ifdef _WIN32
    case trace::API_D3D7:
        wrapperFilename = "ddraw.dll";
        break;
    case trace::API_D3D8:
        wrapperFilename = "d3d8.dll";
        break;
    case trace::API_D3D9:
        wrapperFilename = "d3d9.dll";
        break;
    case trace::API_DXGI:
        wrapperFilename = "dxgitrace.dll";
        useInject = true;
        break;
#endif
    default:
        std::cerr << "error: unsupported API\n";
        return 1;
    }

    os::String wrapperPath = findWrapper(wrapperFilename);
    if (!wrapperPath.length()) {
        std::cerr << "error: failed to find " << wrapperFilename << "\n";
        goto exit;
    }

#if defined(_WIN32)
    if (useInject) {
        args.push_back("inject");
        args.push_back(wrapperPath);
    } else {
        /* On Windows copy the wrapper to the program directory.
         */
        if (!copyWrapper(wrapperPath, argv[0], verbose)) {
            goto exit;
        }
    }
#else  /* !_WIN32 */
    (void)useInject;
#endif /* !_WIN32 */

#if defined(__APPLE__)
    /* On Mac OS X, using DYLD_LIBRARY_PATH, we actually set the
     * directory, not the file. */
    wrapperPath.trimFilename();
#endif

#if defined(TRACE_VARIABLE)
    if (verbose) {
        std::cerr << TRACE_VARIABLE << "=" << wrapperPath.str() << "\n";
    }
    /* FIXME: Don't modify the current environment */
    os::setEnvironment(TRACE_VARIABLE, wrapperPath.str());
#endif /* TRACE_VARIABLE */

    if (output) {
        os::setEnvironment("TRACE_FILE", output);
    }

    for (char * const * arg = argv; *arg; ++arg) {
        args.push_back(*arg);
    }
    args.push_back(NULL);

    if (verbose) {
        const char *sep = "";
        for (unsigned i = 0; i < args.size(); ++i) {
            std::cerr << sep << args[i];
            sep = " ";
        }
        std::cerr << "\n";
    }

    status = os::execute((char * const *)&args[0]);

exit:
#if defined(TRACE_VARIABLE)
    os::unsetEnvironment(TRACE_VARIABLE);
#endif
#if defined(_WIN32)
    if (!useInject) {
        os::String tmpWrapper(argv[0]);
        tmpWrapper.trimFilename();
        tmpWrapper.join(wrapperFilename);
        os::removeFile(tmpWrapper);
    }
#endif

    if (output) {
        os::unsetEnvironment("TRACE_FILE");
    }

    return status;

}

static const char *synopsis = "Generate a new trace by executing the given program.";

static void
usage(void)
{
    std::cout << "usage: apitrace trace [OPTIONS] PROGRAM [ARGS ...]\n"
        << synopsis << "\n"
        "\n"
        "    The given program will be executed with the given arguments.\n"
        "    During execution, all OpenGL calls will be captured to a trace\n"
        "    file. That trace file can then be used\n"
        "    with other apitrace utilities for replay or analysis.\n"
        "\n"
        "    -v, --verbose       verbose output\n"
        "    -a, --api=API       specify API to trace ("
#ifdef _WIN32
                                                      "gl, d3d7, d3d8, d3d9, or dxgi (for d3d10 and higher) "
#else
                                                      "gl or egl"
#endif
                                                      ");\n"
        "                        default is `gl`\n"
        "    -o, --output=TRACE  specify output trace file;\n"
        "                        default is `PROGRAM.trace`\n";
}

const static char *
shortOptions = "+hva:o:";

const static struct option
longOptions[] = {
    {"help", no_argument, 0, 'h'},
    {"verbose", no_argument, 0, 'v'},
    {"api", required_argument, 0, 'a'},
    {"output", required_argument, 0, 'o'},
    {0, 0, 0, 0}
};

static int
command(int argc, char *argv[])
{
    bool verbose = false;
    trace::API api = trace::API_GL;
    const char *output = NULL;

    int opt;
    while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
        switch (opt) {
        case 'h':
            usage();
            return 0;
        case 'v':
            verbose = true;
            break;
        case 'a':
            if (strcmp(optarg, "gl") == 0) {
                api = trace::API_GL;
            } else if (strcmp(optarg, "egl") == 0) {
                api = trace::API_EGL;
            } else if (strcmp(optarg, "d3d7") == 0) {
                api = trace::API_D3D7;
            } else if (strcmp(optarg, "d3d8") == 0) {
                api = trace::API_D3D8;
            } else if (strcmp(optarg, "d3d9") == 0) {
                api = trace::API_D3D9;
            } else if (strcmp(optarg, "dxgi") == 0 ||
                       strcmp(optarg, "d3d10") == 0 ||
                       strcmp(optarg, "d3d10_1") == 0 ||
                       strcmp(optarg, "d3d11") == 0 ||
                       strcmp(optarg, "d3d11_1") == 0) {
                api = trace::API_DXGI;
            } else {
                std::cerr << "error: unknown API `" << optarg << "`\n";
                usage();
                return 1;
            }
            break;
        case 'o':
            output = optarg;
            break;
        default:
            std::cerr << "error: unexpected option `" << opt << "`\n";
            usage();
            return 1;
        }
    }

    if (optind == argc) {
        std::cerr << "error: no command specified\n";
        usage();
        return 1;
    }

    assert(argv[argc] == 0);
    return traceProgram(api, argv + optind, output, verbose);
}

const Command trace_command = {
    "trace",
    synopsis,
    usage,
    command
};
<commit_msg>cli: Inject DLL on windows by default.<commit_after>/*********************************************************************
 *
 * Copyright 2011 Intel Corporation
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *********************************************************************/

#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#include <iostream>

#include "os_string.hpp"
#include "os_process.hpp"

#include "cli.hpp"
#include "cli_resources.hpp"

#if defined(__APPLE__)
#define TRACE_VARIABLE "DYLD_LIBRARY_PATH"
#define GL_TRACE_WRAPPER  "OpenGL"
#elif defined(_WIN32)
#define GL_TRACE_WRAPPER  "opengl32.dll"
#else
#define TRACE_VARIABLE "LD_PRELOAD"
#define GL_TRACE_WRAPPER  "glxtrace.so"
#define EGL_TRACE_WRAPPER  "egltrace.so"
#endif

static inline bool
copyWrapper(const os::String & wrapperPath,
            const char *programPath,
            bool verbose)
{
    os::String wrapperFilename(wrapperPath);
    wrapperFilename.trimDirectory();

    os::String tmpWrapper(programPath);
    tmpWrapper.trimFilename();
    tmpWrapper.join(wrapperFilename);

    if (verbose) {
        std::cerr << wrapperPath << " -> " << tmpWrapper << "\n";
    }

    if (tmpWrapper.exists()) {
        std::cerr << "error: not overwriting " << tmpWrapper << "\n";
        return false;
    }

    if (!os::copyFile(wrapperPath, tmpWrapper, false)) {
        std::cerr << "error: failed to copy " << wrapperPath << " into " << tmpWrapper << "\n";
        return false;
    }

    return true;
}

static int
traceProgram(trace::API api,
             char * const *argv,
             const char *output,
             bool verbose)
{
    const char *wrapperFilename;
    std::vector<const char *> args;
    int status = 1;

    /*
     * TODO: simplify code
     */

    bool useInject = false;
    switch (api) {
    case trace::API_GL:
        wrapperFilename = GL_TRACE_WRAPPER;
        break;
#ifdef EGL_TRACE_WRAPPER
    case trace::API_EGL:
        wrapperFilename = EGL_TRACE_WRAPPER;
        break;
#endif
#ifdef _WIN32
    case trace::API_D3D7:
        wrapperFilename = "ddraw.dll";
        break;
    case trace::API_D3D8:
        wrapperFilename = "d3d8.dll";
        break;
    case trace::API_D3D9:
        wrapperFilename = "d3d9.dll";
        break;
    case trace::API_DXGI:
        wrapperFilename = "dxgitrace.dll";
        useInject = true;
        break;
#endif
    default:
        std::cerr << "error: unsupported API\n";
        return 1;
    }

    os::String wrapperPath = findWrapper(wrapperFilename);
    if (!wrapperPath.length()) {
        std::cerr << "error: failed to find " << wrapperFilename << "\n";
        goto exit;
    }

#if defined(_WIN32)
    useInject = true;
    if (useInject) {
        args.push_back("inject");
        args.push_back(wrapperPath);
    } else {
        /* On Windows copy the wrapper to the program directory.
         */
        if (!copyWrapper(wrapperPath, argv[0], verbose)) {
            goto exit;
        }
    }
#else  /* !_WIN32 */
    (void)useInject;
#endif /* !_WIN32 */

#if defined(__APPLE__)
    /* On Mac OS X, using DYLD_LIBRARY_PATH, we actually set the
     * directory, not the file. */
    wrapperPath.trimFilename();
#endif

#if defined(TRACE_VARIABLE)
    if (verbose) {
        std::cerr << TRACE_VARIABLE << "=" << wrapperPath.str() << "\n";
    }
    /* FIXME: Don't modify the current environment */
    os::setEnvironment(TRACE_VARIABLE, wrapperPath.str());
#endif /* TRACE_VARIABLE */

    if (output) {
        os::setEnvironment("TRACE_FILE", output);
    }

    for (char * const * arg = argv; *arg; ++arg) {
        args.push_back(*arg);
    }
    args.push_back(NULL);

    if (verbose) {
        const char *sep = "";
        for (unsigned i = 0; i < args.size(); ++i) {
            std::cerr << sep << args[i];
            sep = " ";
        }
        std::cerr << "\n";
    }

    status = os::execute((char * const *)&args[0]);

exit:
#if defined(TRACE_VARIABLE)
    os::unsetEnvironment(TRACE_VARIABLE);
#endif
#if defined(_WIN32)
    if (!useInject) {
        os::String tmpWrapper(argv[0]);
        tmpWrapper.trimFilename();
        tmpWrapper.join(wrapperFilename);
        os::removeFile(tmpWrapper);
    }
#endif

    if (output) {
        os::unsetEnvironment("TRACE_FILE");
    }

    return status;

}

static const char *synopsis = "Generate a new trace by executing the given program.";

static void
usage(void)
{
    std::cout << "usage: apitrace trace [OPTIONS] PROGRAM [ARGS ...]\n"
        << synopsis << "\n"
        "\n"
        "    The given program will be executed with the given arguments.\n"
        "    During execution, all OpenGL calls will be captured to a trace\n"
        "    file. That trace file can then be used\n"
        "    with other apitrace utilities for replay or analysis.\n"
        "\n"
        "    -v, --verbose       verbose output\n"
        "    -a, --api=API       specify API to trace ("
#ifdef _WIN32
                                                      "gl, d3d7, d3d8, d3d9, or dxgi (for d3d10 and higher) "
#else
                                                      "gl or egl"
#endif
                                                      ");\n"
        "                        default is `gl`\n"
        "    -o, --output=TRACE  specify output trace file;\n"
        "                        default is `PROGRAM.trace`\n";
}

const static char *
shortOptions = "+hva:o:";

const static struct option
longOptions[] = {
    {"help", no_argument, 0, 'h'},
    {"verbose", no_argument, 0, 'v'},
    {"api", required_argument, 0, 'a'},
    {"output", required_argument, 0, 'o'},
    {0, 0, 0, 0}
};

static int
command(int argc, char *argv[])
{
    bool verbose = false;
    trace::API api = trace::API_GL;
    const char *output = NULL;

    int opt;
    while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
        switch (opt) {
        case 'h':
            usage();
            return 0;
        case 'v':
            verbose = true;
            break;
        case 'a':
            if (strcmp(optarg, "gl") == 0) {
                api = trace::API_GL;
            } else if (strcmp(optarg, "egl") == 0) {
                api = trace::API_EGL;
            } else if (strcmp(optarg, "d3d7") == 0) {
                api = trace::API_D3D7;
            } else if (strcmp(optarg, "d3d8") == 0) {
                api = trace::API_D3D8;
            } else if (strcmp(optarg, "d3d9") == 0) {
                api = trace::API_D3D9;
            } else if (strcmp(optarg, "dxgi") == 0 ||
                       strcmp(optarg, "d3d10") == 0 ||
                       strcmp(optarg, "d3d10_1") == 0 ||
                       strcmp(optarg, "d3d11") == 0 ||
                       strcmp(optarg, "d3d11_1") == 0) {
                api = trace::API_DXGI;
            } else {
                std::cerr << "error: unknown API `" << optarg << "`\n";
                usage();
                return 1;
            }
            break;
        case 'o':
            output = optarg;
            break;
        default:
            std::cerr << "error: unexpected option `" << opt << "`\n";
            usage();
            return 1;
        }
    }

    if (optind == argc) {
        std::cerr << "error: no command specified\n";
        usage();
        return 1;
    }

    assert(argv[argc] == 0);
    return traceProgram(api, argv + optind, output, verbose);
}

const Command trace_command = {
    "trace",
    synopsis,
    usage,
    command
};
<|endoftext|>


<commit_before>///
// CrabLlvm -- Abstract Interpretation-based Analyzer for LLVM bitcode
///

#include "llvm/LinkAllPasses.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/IR/Verifier.h"
#include "crab_llvm/config.h"

#ifdef HAVE_LLVM_SEAHORN
#include "llvm_seahorn/Transforms/Scalar.h"
#endif

#include "crab_llvm/Passes.hh"
#include "crab_llvm/CrabLlvm.hh"
#include "crab_llvm/Transforms/InsertInvariants.hh"
#include "crab/common/debug.hpp"

static llvm::cl::opt<std::string>
InputFilename(llvm::cl::Positional, llvm::cl::desc("<input LLVM bitcode file>"),
              llvm::cl::Required, llvm::cl::value_desc("filename"));

static llvm::cl::opt<std::string>
OutputFilename("o", llvm::cl::desc("Override output filename"),
               llvm::cl::init(""), llvm::cl::value_desc("filename"));

static llvm::cl::opt<bool>
OutputAssembly("S", llvm::cl::desc("Write output as LLVM assembly"));

static llvm::cl::opt<std::string>
AsmOutputFilename("oll", llvm::cl::desc("Output analyzed bitcode"),
               llvm::cl::init(""), llvm::cl::value_desc("filename"));

static llvm::cl::opt<std::string>
DefaultDataLayout("default-data-layout",
                  llvm::cl::desc("data layout string to use if not specified by module"),
                  llvm::cl::init(""), llvm::cl::value_desc("layout-string"));

static llvm::cl::opt<bool>
NoCrab("no-crab",
        llvm::cl::desc("Output preprocessed bitcode but disabling Crab analysis"),
        llvm::cl::init(false),
        llvm::cl::Hidden);

static llvm::cl::opt<bool>
TurnUndefNondet("crab-turn-undef-nondet",
                 llvm::cl::desc("Turn undefined behaviour into non-determinism"),
                 llvm::cl::init(false),
                 llvm::cl::Hidden);

static llvm::cl::opt<bool>
LowerUnsignedICmp("crab-lower-unsigned-icmp",
	 llvm::cl::desc("Lower ULT and ULE instructions"),
	 llvm::cl::init(false));

static llvm::cl::opt<bool>
LowerCstExpr("crab-lower-constant-expr",
	 llvm::cl::desc("Lower constant expressions to instructions"),
	 llvm::cl::init(true));

static llvm::cl::opt<bool>
LowerInvoke("crab-lower-invoke",
	 llvm::cl::desc("Lower invoke instructions"),
	 llvm::cl::init(true));

static llvm::cl::opt<bool>
LowerSwitch("crab-lower-switch",
	 llvm::cl::desc("Lower switch instructions"),
	 llvm::cl::init(true));

static llvm::cl::opt<bool>
LowerSelect("crab-lower-select",
             llvm::cl::desc("Lower all select instructions"),
             llvm::cl::init(false));

static llvm::cl::opt<bool>
PromoteAssume("crab-promote-assume",
	       llvm::cl::desc("Promote verifier.assume to llvm.assume intrinsics"),
	       llvm::cl::init(false));

/* logging and verbosity */

struct LogOpt {
  void operator=(const std::string &tag) const
  { crab::CrabEnableLog(tag); }
};

LogOpt loc;

static llvm::cl::opt<LogOpt, true, llvm::cl::parser<std::string> >
LogClOption("log",
             llvm::cl::desc("Enable specified log level"),
             llvm::cl::location(loc),
             llvm::cl::value_desc("string"),
             llvm::cl::ValueRequired, llvm::cl::ZeroOrMore);

struct VerboseOpt {
  void operator=(unsigned level) const
  { crab::CrabEnableVerbosity(level); }
};

VerboseOpt verbose;

static llvm::cl::opt<VerboseOpt, true, llvm::cl::parser<unsigned> >
CrabVerbose("crab-verbose",
	    llvm::cl::desc("Enable verbose messages"),
	    llvm::cl::location(verbose),
	    llvm::cl::value_desc("uint"));

struct WarningOpt {
  void operator=(bool val) const
  { crab::CrabEnableWarningMsg(val); }
};

WarningOpt warning;

static llvm::cl::opt<WarningOpt, true, llvm::cl::parser<bool> >
CrabEnableWarning("crab-enable-warnings",
	    llvm::cl::desc("Enable warning messages"),
	    llvm::cl::location(warning),
	    llvm::cl::value_desc("bool"));

struct SanityChecksOpt {
  void operator=(bool val) const
  { crab::CrabEnableSanityChecks(val); }
};

SanityChecksOpt sanity;

static llvm::cl::opt<SanityChecksOpt, true, llvm::cl::parser<bool> >
CrabSanityChecks("crab-sanity-checks",
	    llvm::cl::desc("Enable sanity checks"),
	    llvm::cl::location(sanity),
	    llvm::cl::value_desc("bool"));

using namespace crab_llvm;

// removes extension from filename if there is one
std::string getFileName(const std::string &str) {
  std::string filename = str;
  size_t lastdot = str.find_last_of(".");
  if (lastdot != std::string::npos)
    filename = str.substr(0, lastdot);
  return filename;
}

int main(int argc, char **argv) {
  llvm::llvm_shutdown_obj shutdown;  // calls llvm_shutdown() on exit
  llvm::cl::ParseCommandLineOptions(argc, argv,
  "CrabLlvm-- Abstract Interpretation-based Analyzer of LLVM bitcode\n");

  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
  llvm::PrettyStackTraceProgram PSTP(argc, argv);
  llvm::EnableDebugBuffering = true;

  std::error_code error_code;
  llvm::SMDiagnostic err;
  static llvm::LLVMContext context;
  std::unique_ptr<llvm::Module> module;
  std::unique_ptr<llvm::tool_output_file> output;
  std::unique_ptr<llvm::tool_output_file> asmOutput;

  module = llvm::parseIRFile(InputFilename, err, context);
  if (!module) {
    if (llvm::errs().has_colors()) llvm::errs().changeColor(llvm::raw_ostream::RED);
    llvm::errs() << "error: "
                 << "Bitcode was not properly read; " << err.getMessage() << "\n";
    if (llvm::errs().has_colors()) llvm::errs().resetColor();
    return 3;
  }

  if (!AsmOutputFilename.empty())
    asmOutput =
      llvm::make_unique<llvm::tool_output_file>(AsmOutputFilename.c_str(), error_code,
                                                llvm::sys::fs::F_Text);
  if (error_code) {
    if (llvm::errs().has_colors())
      llvm::errs().changeColor(llvm::raw_ostream::RED);
    llvm::errs() << "error: Could not open " << AsmOutputFilename << ": "
                 << error_code.message() << "\n";
    if (llvm::errs().has_colors()) llvm::errs().resetColor();
    return 3;
  }

  if (!OutputFilename.empty())
    output = llvm::make_unique<llvm::tool_output_file>
      (OutputFilename.c_str(), error_code, llvm::sys::fs::F_None);

  if (error_code) {
    if (llvm::errs().has_colors()) llvm::errs().changeColor(llvm::raw_ostream::RED);
    llvm::errs() << "error: Could not open " << OutputFilename << ": "
                 << error_code.message() << "\n";
    if (llvm::errs().has_colors()) llvm::errs().resetColor();
    return 3;
  }

  ///////////////////////////////
  // initialise and run passes //
  ///////////////////////////////

  llvm::legacy::PassManager pass_manager;
  llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
  llvm::initializeAnalysis(Registry);

  /// call graph and other IPA passes
  // llvm::initializeIPA (Registry);
  // XXX: porting to 3.8
  llvm::initializeCallGraphWrapperPassPass(Registry);
  // XXX: commented while porting to 5.0
  //llvm::initializeCallGraphPrinterPass(Registry);
  llvm::initializeCallGraphViewerPass(Registry);
  // XXX: not sure if needed anymore
  llvm::initializeGlobalsAAWrapperPassPass(Registry);

  // add an appropriate DataLayout instance for the module
  const llvm::DataLayout *dl = &module->getDataLayout();
  if (!dl && !DefaultDataLayout.empty())
  {
    module->setDataLayout(DefaultDataLayout);
    dl = &module->getDataLayout();
  }

  assert(dl && "Could not find Data Layout for the module");

  /**
   * Here only passes that are strictly necessary to avoid crashes or
   * useless results. Passes that are only for improving precision
   * should be run in crabllvm-pp.
   **/

  // kill unused internal global
  pass_manager.add(llvm::createGlobalDCEPass());
  pass_manager.add(crab_llvm::createRemoveUnreachableBlocksPass());

  // -- promote alloca's to registers
  pass_manager.add(llvm::createPromoteMemoryToRegisterPass());
  #ifdef HAVE_LLVM_SEAHORN
  if (TurnUndefNondet) {
    // -- Turn undef into nondet
    pass_manager.add(llvm_seahorn::createNondetInitPass());
  }
  #endif
  if (LowerInvoke) {
    // -- lower invoke's
    pass_manager.add(llvm::createLowerInvokePass());
    // cleanup after lowering invoke's
    pass_manager.add(llvm::createCFGSimplificationPass());
  }
  // -- ensure one single exit point per function
  pass_manager.add(llvm::createUnifyFunctionExitNodesPass());
  // -- remove unreachable blocks
  pass_manager.add(crab_llvm::createRemoveUnreachableBlocksPass());
  if (LowerSwitch) {
    // -- remove switch constructions
    pass_manager.add(llvm::createLowerSwitchPass());
    // cleanup after lowering switches
    pass_manager.add(llvm::createCFGSimplificationPass());
  }
  // -- lower constant expressions to instructions
  if (LowerCstExpr) {
    pass_manager.add(crab_llvm::createLowerCstExprPass());
    // cleanup after lowering constant expressions
    pass_manager.add(llvm::createDeadCodeEliminationPass());
  }
  #ifdef HAVE_LLVM_SEAHORN
  if (TurnUndefNondet) {
    pass_manager.add(llvm_seahorn::createDeadNondetElimPass());
  }
  #endif

  // -- lower ULT and ULE instructions
  if(LowerUnsignedICmp) {
    pass_manager.add(crab_llvm::createLowerUnsignedICmpPass());
    // cleanup unnecessary and unreachable blocks
    pass_manager.add(llvm::createCFGSimplificationPass());
    pass_manager.add(crab_llvm::createRemoveUnreachableBlocksPass());
  }

  // -- must be the last ones before running crab.
  if (LowerSelect) {
    pass_manager.add(crab_llvm::createLowerSelectPass());
  }

  if (!NoCrab) {
    /// -- run the crab analyzer
    pass_manager.add(new crab_llvm::CrabLlvmPass());
  }

  if(!AsmOutputFilename.empty())
    pass_manager.add(createPrintModulePass(asmOutput->os()));

  if (!NoCrab) {
    // -- perform dead code elimination and insert invariants as
    // -- assume instructions
    pass_manager.add(new crab_llvm::InsertInvariants());
    // -- simplify invariants added in the bytecode.
    #ifdef HAVE_LLVM_SEAHORN
    pass_manager.add(llvm_seahorn::createInstructionCombiningPass());
    #else
    pass_manager.add(llvm::createInstructionCombiningPass());
    #endif
    if (PromoteAssume) {
      // -- promote verifier.assume to llvm.assume intrinsics
      pass_manager.add(crab_llvm::createPromoteAssumePass());
    }
  }

  if (!OutputFilename.empty()) {
    if (OutputAssembly)
      pass_manager.add(createPrintModulePass(output->os()));
    else
      pass_manager.add(createBitcodeWriterPass(output->os()));
  }

  pass_manager.run(*module.get());

  if (!AsmOutputFilename.empty()) asmOutput->keep();
  if (!OutputFilename.empty()) output->keep();

  return 0;
}
<commit_msg>Unify exit nodes after lower select and unsigned icmp insts<commit_after>///
// CrabLlvm -- Abstract Interpretation-based Analyzer for LLVM bitcode
///

#include "llvm/LinkAllPasses.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/IR/Verifier.h"
#include "crab_llvm/config.h"

#ifdef HAVE_LLVM_SEAHORN
#include "llvm_seahorn/Transforms/Scalar.h"
#endif

#include "crab_llvm/Passes.hh"
#include "crab_llvm/CrabLlvm.hh"
#include "crab_llvm/Transforms/InsertInvariants.hh"
#include "crab/common/debug.hpp"

static llvm::cl::opt<std::string>
InputFilename(llvm::cl::Positional, llvm::cl::desc("<input LLVM bitcode file>"),
              llvm::cl::Required, llvm::cl::value_desc("filename"));

static llvm::cl::opt<std::string>
OutputFilename("o", llvm::cl::desc("Override output filename"),
               llvm::cl::init(""), llvm::cl::value_desc("filename"));

static llvm::cl::opt<bool>
OutputAssembly("S", llvm::cl::desc("Write output as LLVM assembly"));

static llvm::cl::opt<std::string>
AsmOutputFilename("oll", llvm::cl::desc("Output analyzed bitcode"),
               llvm::cl::init(""), llvm::cl::value_desc("filename"));

static llvm::cl::opt<std::string>
DefaultDataLayout("default-data-layout",
                  llvm::cl::desc("data layout string to use if not specified by module"),
                  llvm::cl::init(""), llvm::cl::value_desc("layout-string"));

static llvm::cl::opt<bool>
NoCrab("no-crab",
        llvm::cl::desc("Output preprocessed bitcode but disabling Crab analysis"),
        llvm::cl::init(false),
        llvm::cl::Hidden);

static llvm::cl::opt<bool>
TurnUndefNondet("crab-turn-undef-nondet",
                 llvm::cl::desc("Turn undefined behaviour into non-determinism"),
                 llvm::cl::init(false),
                 llvm::cl::Hidden);

static llvm::cl::opt<bool>
LowerUnsignedICmp("crab-lower-unsigned-icmp",
	 llvm::cl::desc("Lower ULT and ULE instructions"),
	 llvm::cl::init(false));

static llvm::cl::opt<bool>
LowerCstExpr("crab-lower-constant-expr",
	 llvm::cl::desc("Lower constant expressions to instructions"),
	 llvm::cl::init(true));

static llvm::cl::opt<bool>
LowerInvoke("crab-lower-invoke",
	 llvm::cl::desc("Lower invoke instructions"),
	 llvm::cl::init(true));

static llvm::cl::opt<bool>
LowerSwitch("crab-lower-switch",
	 llvm::cl::desc("Lower switch instructions"),
	 llvm::cl::init(true));

static llvm::cl::opt<bool>
LowerSelect("crab-lower-select",
             llvm::cl::desc("Lower all select instructions"),
             llvm::cl::init(false));

static llvm::cl::opt<bool>
PromoteAssume("crab-promote-assume",
	       llvm::cl::desc("Promote verifier.assume to llvm.assume intrinsics"),
	       llvm::cl::init(false));

/* logging and verbosity */

struct LogOpt {
  void operator=(const std::string &tag) const
  { crab::CrabEnableLog(tag); }
};

LogOpt loc;

static llvm::cl::opt<LogOpt, true, llvm::cl::parser<std::string> >
LogClOption("log",
             llvm::cl::desc("Enable specified log level"),
             llvm::cl::location(loc),
             llvm::cl::value_desc("string"),
             llvm::cl::ValueRequired, llvm::cl::ZeroOrMore);

struct VerboseOpt {
  void operator=(unsigned level) const
  { crab::CrabEnableVerbosity(level); }
};

VerboseOpt verbose;

static llvm::cl::opt<VerboseOpt, true, llvm::cl::parser<unsigned> >
CrabVerbose("crab-verbose",
	    llvm::cl::desc("Enable verbose messages"),
	    llvm::cl::location(verbose),
	    llvm::cl::value_desc("uint"));

struct WarningOpt {
  void operator=(bool val) const
  { crab::CrabEnableWarningMsg(val); }
};

WarningOpt warning;

static llvm::cl::opt<WarningOpt, true, llvm::cl::parser<bool> >
CrabEnableWarning("crab-enable-warnings",
	    llvm::cl::desc("Enable warning messages"),
	    llvm::cl::location(warning),
	    llvm::cl::value_desc("bool"));

struct SanityChecksOpt {
  void operator=(bool val) const
  { crab::CrabEnableSanityChecks(val); }
};

SanityChecksOpt sanity;

static llvm::cl::opt<SanityChecksOpt, true, llvm::cl::parser<bool> >
CrabSanityChecks("crab-sanity-checks",
	    llvm::cl::desc("Enable sanity checks"),
	    llvm::cl::location(sanity),
	    llvm::cl::value_desc("bool"));

using namespace crab_llvm;

// removes extension from filename if there is one
std::string getFileName(const std::string &str) {
  std::string filename = str;
  size_t lastdot = str.find_last_of(".");
  if (lastdot != std::string::npos)
    filename = str.substr(0, lastdot);
  return filename;
}

int main(int argc, char **argv) {
  llvm::llvm_shutdown_obj shutdown;  // calls llvm_shutdown() on exit
  llvm::cl::ParseCommandLineOptions(argc, argv,
  "CrabLlvm-- Abstract Interpretation-based Analyzer of LLVM bitcode\n");

  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
  llvm::PrettyStackTraceProgram PSTP(argc, argv);
  llvm::EnableDebugBuffering = true;

  std::error_code error_code;
  llvm::SMDiagnostic err;
  static llvm::LLVMContext context;
  std::unique_ptr<llvm::Module> module;
  std::unique_ptr<llvm::tool_output_file> output;
  std::unique_ptr<llvm::tool_output_file> asmOutput;

  module = llvm::parseIRFile(InputFilename, err, context);
  if (!module) {
    if (llvm::errs().has_colors()) llvm::errs().changeColor(llvm::raw_ostream::RED);
    llvm::errs() << "error: "
                 << "Bitcode was not properly read; " << err.getMessage() << "\n";
    if (llvm::errs().has_colors()) llvm::errs().resetColor();
    return 3;
  }

  if (!AsmOutputFilename.empty())
    asmOutput =
      llvm::make_unique<llvm::tool_output_file>(AsmOutputFilename.c_str(), error_code,
                                                llvm::sys::fs::F_Text);
  if (error_code) {
    if (llvm::errs().has_colors())
      llvm::errs().changeColor(llvm::raw_ostream::RED);
    llvm::errs() << "error: Could not open " << AsmOutputFilename << ": "
                 << error_code.message() << "\n";
    if (llvm::errs().has_colors()) llvm::errs().resetColor();
    return 3;
  }

  if (!OutputFilename.empty())
    output = llvm::make_unique<llvm::tool_output_file>
      (OutputFilename.c_str(), error_code, llvm::sys::fs::F_None);

  if (error_code) {
    if (llvm::errs().has_colors()) llvm::errs().changeColor(llvm::raw_ostream::RED);
    llvm::errs() << "error: Could not open " << OutputFilename << ": "
                 << error_code.message() << "\n";
    if (llvm::errs().has_colors()) llvm::errs().resetColor();
    return 3;
  }

  ///////////////////////////////
  // initialise and run passes //
  ///////////////////////////////

  llvm::legacy::PassManager pass_manager;
  llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
  llvm::initializeAnalysis(Registry);

  /// call graph and other IPA passes
  // llvm::initializeIPA (Registry);
  // XXX: porting to 3.8
  llvm::initializeCallGraphWrapperPassPass(Registry);
  // XXX: commented while porting to 5.0
  //llvm::initializeCallGraphPrinterPass(Registry);
  llvm::initializeCallGraphViewerPass(Registry);
  // XXX: not sure if needed anymore
  llvm::initializeGlobalsAAWrapperPassPass(Registry);

  // add an appropriate DataLayout instance for the module
  const llvm::DataLayout *dl = &module->getDataLayout();
  if (!dl && !DefaultDataLayout.empty())
  {
    module->setDataLayout(DefaultDataLayout);
    dl = &module->getDataLayout();
  }

  assert(dl && "Could not find Data Layout for the module");

  /**
   * Here only passes that are strictly necessary to avoid crashes or
   * useless results. Passes that are only for improving precision
   * should be run in crabllvm-pp.
   **/

  // kill unused internal global
  pass_manager.add(llvm::createGlobalDCEPass());
  pass_manager.add(crab_llvm::createRemoveUnreachableBlocksPass());

  // -- promote alloca's to registers
  pass_manager.add(llvm::createPromoteMemoryToRegisterPass());
  #ifdef HAVE_LLVM_SEAHORN
  if (TurnUndefNondet) {
    // -- Turn undef into nondet
    pass_manager.add(llvm_seahorn::createNondetInitPass());
  }
  #endif
  if (LowerInvoke) {
    // -- lower invoke's
    pass_manager.add(llvm::createLowerInvokePass());
    // cleanup after lowering invoke's
    pass_manager.add(llvm::createCFGSimplificationPass());
  }
  // -- ensure one single exit point per function
  pass_manager.add(llvm::createUnifyFunctionExitNodesPass());
  // -- remove unreachable blocks
  pass_manager.add(crab_llvm::createRemoveUnreachableBlocksPass());
  if (LowerSwitch) {
    // -- remove switch constructions
    pass_manager.add(llvm::createLowerSwitchPass());
    // cleanup after lowering switches
    pass_manager.add(llvm::createCFGSimplificationPass());
  }
  // -- lower constant expressions to instructions
  if (LowerCstExpr) {
    pass_manager.add(crab_llvm::createLowerCstExprPass());
    // cleanup after lowering constant expressions
    pass_manager.add(llvm::createDeadCodeEliminationPass());
  }
  #ifdef HAVE_LLVM_SEAHORN
  if (TurnUndefNondet) {
    pass_manager.add(llvm_seahorn::createDeadNondetElimPass());
  }
  #endif

  // -- lower ULT and ULE instructions
  if(LowerUnsignedICmp) {
    pass_manager.add(crab_llvm::createLowerUnsignedICmpPass());
    // cleanup unnecessary and unreachable blocks
    pass_manager.add(llvm::createCFGSimplificationPass());
    pass_manager.add(crab_llvm::createRemoveUnreachableBlocksPass());
  }

  // -- must be the last ones before running crab.
  if (LowerSelect) {
    pass_manager.add(crab_llvm::createLowerSelectPass());
  }

  // -- ensure one single exit point per function
  // LowerUnsignedIcmpPass and LowerSelect can add multiple returns.
  pass_manager.add(llvm::createUnifyFunctionExitNodesPass());

  if (!NoCrab) {
    /// -- run the crab analyzer
    pass_manager.add(new crab_llvm::CrabLlvmPass());
  }

  if(!AsmOutputFilename.empty())
    pass_manager.add(createPrintModulePass(asmOutput->os()));

  if (!NoCrab) {
    // -- perform dead code elimination and insert invariants as
    // -- assume instructions
    pass_manager.add(new crab_llvm::InsertInvariants());
    // -- simplify invariants added in the bytecode.
    #ifdef HAVE_LLVM_SEAHORN
    pass_manager.add(llvm_seahorn::createInstructionCombiningPass());
    #else
    pass_manager.add(llvm::createInstructionCombiningPass());
    #endif
    if (PromoteAssume) {
      // -- promote verifier.assume to llvm.assume intrinsics
      pass_manager.add(crab_llvm::createPromoteAssumePass());
    }
  }

  if (!OutputFilename.empty()) {
    if (OutputAssembly)
      pass_manager.add(createPrintModulePass(output->os()));
    else
      pass_manager.add(createBitcodeWriterPass(output->os()));
  }

  pass_manager.run(*module.get());

  if (!AsmOutputFilename.empty()) asmOutput->keep();
  if (!OutputFilename.empty()) output->keep();

  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Bugfix: create OpenGL 3.0 context.<commit_after><|endoftext|>


<commit_before>//===- opt.cpp - The LLVM Modular Optimizer -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineImpls.h"
#include "llvm/Support/PassNameParser.h"
#include "llvm/System/Signals.h"
#include "Support/SystemUtils.h"
#include <fstream>
#include <memory>
#include <algorithm>

using namespace llvm;

// The OptimizationList is automatically populated with registered Passes by the
// PassNameParser.
//
static cl::list<const PassInfo*, bool,
                FilteredPassNameParser<PassInfo::Optimization> >
OptimizationList(cl::desc("Optimizations available:"));

// Other command line options...
//
static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));

static cl::opt<std::string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"), cl::init("-"));

static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
PrintEachXForm("p", cl::desc("Print module after each transformation"));

static cl::opt<bool>
NoOutput("disable-output",
         cl::desc("Do not write result bytecode file"), cl::Hidden);

static cl::opt<bool>
NoVerify("disable-verify", cl::desc("Do not verify result module"), cl::Hidden);

static cl::opt<bool>
Quiet("q", cl::desc("Don't print 'program modified' message"));

static cl::alias
QuietA("quiet", cl::desc("Alias for -q"), cl::aliasopt(Quiet));

//===----------------------------------------------------------------------===//
// main for opt
//
int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");
  PrintStackTraceOnErrorSignal();

  // Allocate a full target machine description only if necessary...
  // FIXME: The choice of target should be controllable on the command line.
  std::auto_ptr<TargetMachine> target;

  TargetMachine* TM = NULL;
  std::string ErrorMessage;

  // Load the input module...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename, &ErrorMessage));
  if (M.get() == 0) {
    std::cerr << argv[0] << ": ";
    if (ErrorMessage.size())
      std::cerr << ErrorMessage << "\n";
    else
      std::cerr << "bytecode didn't read correctly.\n";
    return 1;
  }

  // Figure out what stream we are supposed to write to...
  std::ostream *Out = &std::cout;  // Default to printing to stdout...
  if (OutputFilename != "-") {
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      std::cerr << argv[0] << ": error opening '" << OutputFilename
                << "': file exists!\n"
                << "Use -f command line argument to force output\n";
      return 1;
    }
    Out = new std::ofstream(OutputFilename.c_str());

    if (!Out->good()) {
      std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
      return 1;
    }

    // Make sure that the Output file gets unlinked from the disk if we get a
    // SIGINT
    RemoveFileOnSignal(OutputFilename);
  }

  // If the output is set to be emitted to standard out, and standard out is a
  // console, print out a warning message and refuse to do it.  We don't impress
  // anyone by spewing tons of binary goo to a terminal.
  if (Out == &std::cout && isStandardOutAConsole() && !Force && !NoOutput
      && !Quiet) {
    std::cerr << "WARNING: It looks like you're attempting to print out a "
              << "bytecode file.  I'm\ngoing to pretend you didn't ask me to do"
              << " this (for your own good).  If you\nREALLY want to taste LLVM"
              << " bytecode first hand, you can force output with the\n'-f'"
              << " option.\n\n";
    NoOutput = true;
  }

  // Create a PassManager to hold and optimize the collection of passes we are
  // about to build...
  //
  PassManager Passes;

  // Add an appropriate TargetData instance for this module...
  Passes.add(new TargetData("opt", M.get()));

  // Create a new optimization pass for each one specified on the command line
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    const PassInfo *Opt = OptimizationList[i];

    if (Opt->getNormalCtor())
      Passes.add(Opt->getNormalCtor()());
    else if (Opt->getTargetCtor()) {
#if 0
      if (target.get() == NULL)
        target.reset(allocateSparcTargetMachine()); // FIXME: target option
#endif
      assert(target.get() && "Could not allocate target machine!");
      Passes.add(Opt->getTargetCtor()(*target.get()));
    } else
      std::cerr << argv[0] << ": cannot create pass: " << Opt->getPassName()
                << "\n";

    if (PrintEachXForm)
      Passes.add(new PrintModulePass(&std::cerr));
  }

  // Check that the module is well formed on completion of optimization
  if (!NoVerify)
    Passes.add(createVerifierPass());

  // Write bytecode out to disk or cout as the last step...
  if (!NoOutput)
    Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

  // Now that we have all of the passes ready, run them.
  if (Passes.run(*M.get()) )
    return 0;

  return 0;
}
<commit_msg>Neuter the -q option.  Stop printing the "program modified" message, ever<commit_after>//===- opt.cpp - The LLVM Modular Optimizer -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineImpls.h"
#include "llvm/Support/PassNameParser.h"
#include "llvm/System/Signals.h"
#include "Support/SystemUtils.h"
#include <fstream>
#include <memory>
#include <algorithm>

using namespace llvm;

// The OptimizationList is automatically populated with registered Passes by the
// PassNameParser.
//
static cl::list<const PassInfo*, bool,
                FilteredPassNameParser<PassInfo::Optimization> >
OptimizationList(cl::desc("Optimizations available:"));

// Other command line options...
//
static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));

static cl::opt<std::string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"), cl::init("-"));

static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
PrintEachXForm("p", cl::desc("Print module after each transformation"));

static cl::opt<bool>
NoOutput("disable-output",
         cl::desc("Do not write result bytecode file"), cl::Hidden);

static cl::opt<bool>
NoVerify("disable-verify", cl::desc("Do not verify result module"), cl::Hidden);

static cl::opt<bool>
Quiet("q", cl::desc("Obsolete option"), cl::Hidden);

static cl::alias
QuietA("quiet", cl::desc("Alias for -q"), cl::aliasopt(Quiet));

//===----------------------------------------------------------------------===//
// main for opt
//
int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");
  PrintStackTraceOnErrorSignal();

  // Allocate a full target machine description only if necessary...
  // FIXME: The choice of target should be controllable on the command line.
  std::auto_ptr<TargetMachine> target;

  TargetMachine* TM = NULL;
  std::string ErrorMessage;

  // Load the input module...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename, &ErrorMessage));
  if (M.get() == 0) {
    std::cerr << argv[0] << ": ";
    if (ErrorMessage.size())
      std::cerr << ErrorMessage << "\n";
    else
      std::cerr << "bytecode didn't read correctly.\n";
    return 1;
  }

  // Figure out what stream we are supposed to write to...
  std::ostream *Out = &std::cout;  // Default to printing to stdout...
  if (OutputFilename != "-") {
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      std::cerr << argv[0] << ": error opening '" << OutputFilename
                << "': file exists!\n"
                << "Use -f command line argument to force output\n";
      return 1;
    }
    Out = new std::ofstream(OutputFilename.c_str());

    if (!Out->good()) {
      std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
      return 1;
    }

    // Make sure that the Output file gets unlinked from the disk if we get a
    // SIGINT
    RemoveFileOnSignal(OutputFilename);
  }

  // If the output is set to be emitted to standard out, and standard out is a
  // console, print out a warning message and refuse to do it.  We don't impress
  // anyone by spewing tons of binary goo to a terminal.
  if (Out == &std::cout && isStandardOutAConsole() && !Force && !NoOutput
      && !Quiet) {
    std::cerr << "WARNING: It looks like you're attempting to print out a "
              << "bytecode file.  I'm\ngoing to pretend you didn't ask me to do"
              << " this (for your own good).  If you\nREALLY want to taste LLVM"
              << " bytecode first hand, you can force output with the\n'-f'"
              << " option.\n\n";
    NoOutput = true;
  }

  // Create a PassManager to hold and optimize the collection of passes we are
  // about to build...
  //
  PassManager Passes;

  // Add an appropriate TargetData instance for this module...
  Passes.add(new TargetData("opt", M.get()));

  // Create a new optimization pass for each one specified on the command line
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    const PassInfo *Opt = OptimizationList[i];

    if (Opt->getNormalCtor())
      Passes.add(Opt->getNormalCtor()());
    else if (Opt->getTargetCtor()) {
#if 0
      if (target.get() == NULL)
        target.reset(allocateSparcTargetMachine()); // FIXME: target option
#endif
      assert(target.get() && "Could not allocate target machine!");
      Passes.add(Opt->getTargetCtor()(*target.get()));
    } else
      std::cerr << argv[0] << ": cannot create pass: " << Opt->getPassName()
                << "\n";

    if (PrintEachXForm)
      Passes.add(new PrintModulePass(&std::cerr));
  }

  // Check that the module is well formed on completion of optimization
  if (!NoVerify)
    Passes.add(createVerifierPass());

  // Write bytecode out to disk or cout as the last step...
  if (!NoOutput)
    Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

  // Now that we have all of the passes ready, run them.
  Passes.run(*M.get());

  return 0;
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <memory>
#include <vector>

#include "libs/catch/catch.hpp"
#include "libs/exceptionpp/exception.h"

#include "src/simpleconcurrentcache.h"
#include "src/simpleserialcache.h"
#include "src/simpleline.h"

TEST_CASE("cachepp|concurrentcache") {
	std::shared_ptr<cachepp::SimpleConcurrentCache<cachepp::SimpleLine>> c (new cachepp::SimpleConcurrentCache<cachepp::SimpleLine>(2));
}

TEST_CASE("cachepp|serialcache") {
	std::shared_ptr<cachepp::SimpleSerialCache<cachepp::SimpleLine>> c (new cachepp::SimpleSerialCache<cachepp::SimpleLine>(2));

	std::vector<std::shared_ptr<cachepp::SimpleLine>> v;
	for(size_t i = 0; i < 10; ++i) {
		v.push_back(std::shared_ptr<cachepp::SimpleLine> (new cachepp::SimpleLine(rand(), false)));
	}

	for(size_t i = 0; i < 10; ++i) {
		REQUIRE(v.at(i)->get_is_loaded() == false);
	}

	// test cache line juggling
	for(size_t i = 0; i < 10; ++i) {
		c->acquire(v.at(i));
		REQUIRE(v.at(i)->get_is_loaded() == true);
	}

	size_t loaded_lines = 0;
	for(size_t i = 0; i < 10; ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 2);

	c->clear();

	loaded_lines = 0;
	for(size_t i = 0; i < 10; ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 0);

	// test selection policy
	c->acquire(v.at(0));
	c->acquire(v.at(1));

	REQUIRE_THROWS_AS(c->access(v.at(2)), exceptionpp::RuntimeError);

	c->access(v.at(0));
	c->acquire(v.at(2));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(1)->get_is_loaded() == false);
	REQUIRE(v.at(2)->get_is_loaded() == true);

	c->acquire(v.at(3));

	REQUIRE(v.at(0)->get_is_loaded() == false);
	REQUIRE(v.at(2)->get_is_loaded() == true);
	REQUIRE(v.at(3)->get_is_loaded() == true);
}
<commit_msg>added concurrent cache tests<commit_after>#include <cstdlib>
#include <memory>
#include <vector>

#include "libs/catch/catch.hpp"
#include "libs/exceptionpp/exception.h"

#include "src/simpleconcurrentcache.h"
#include "src/simpleserialcache.h"
#include "src/simpleline.h"

TEST_CASE("cachepp|concurrentcache") {
	std::shared_ptr<cachepp::SimpleConcurrentCache<cachepp::SimpleLine>> c (new cachepp::SimpleConcurrentCache<cachepp::SimpleLine>(2));

	std::vector<std::shared_ptr<cachepp::SimpleLine>> v;
	for(size_t i = 0; i < 10; ++i) {
		v.push_back(std::shared_ptr<cachepp::SimpleLine> (new cachepp::SimpleLine(rand(), false)));
	}

	for(size_t i = 0; i < 10; ++i) {
		REQUIRE(v.at(i)->get_is_loaded() == false);
	}

	// test cache line juggling
	for(size_t i = 0; i < 10; ++i) {
		c->acquire(v.at(i));
		REQUIRE(v.at(i)->get_is_loaded() == true);
	}

	size_t loaded_lines = 0;
	for(size_t i = 0; i < 10; ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 2);

	c->clear();

	loaded_lines = 0;
	for(size_t i = 0; i < 10; ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 0);

	// test selection policy
	c->acquire(v.at(0));
	c->acquire(v.at(1));

	REQUIRE_THROWS_AS(c->access(v.at(2)), exceptionpp::RuntimeError);

	c->access(v.at(0));
	c->acquire(v.at(2));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(1)->get_is_loaded() == false);
	REQUIRE(v.at(2)->get_is_loaded() == true);

	c->acquire(v.at(3));

	REQUIRE(v.at(0)->get_is_loaded() == false);
	REQUIRE(v.at(2)->get_is_loaded() == true);
	REQUIRE(v.at(3)->get_is_loaded() == true);
}

TEST_CASE("cachepp|serialcache") {
	std::shared_ptr<cachepp::SimpleSerialCache<cachepp::SimpleLine>> c (new cachepp::SimpleSerialCache<cachepp::SimpleLine>(2));

	std::vector<std::shared_ptr<cachepp::SimpleLine>> v;
	for(size_t i = 0; i < 10; ++i) {
		v.push_back(std::shared_ptr<cachepp::SimpleLine> (new cachepp::SimpleLine(rand(), false)));
	}

	for(size_t i = 0; i < 10; ++i) {
		REQUIRE(v.at(i)->get_is_loaded() == false);
	}

	// test cache line juggling
	for(size_t i = 0; i < 10; ++i) {
		c->acquire(v.at(i));
		REQUIRE(v.at(i)->get_is_loaded() == true);
	}

	size_t loaded_lines = 0;
	for(size_t i = 0; i < 10; ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 2);

	c->clear();

	loaded_lines = 0;
	for(size_t i = 0; i < 10; ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 0);

	// test selection policy
	c->acquire(v.at(0));
	c->acquire(v.at(1));

	REQUIRE_THROWS_AS(c->access(v.at(2)), exceptionpp::RuntimeError);

	c->access(v.at(0));
	c->acquire(v.at(2));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(1)->get_is_loaded() == false);
	REQUIRE(v.at(2)->get_is_loaded() == true);

	c->acquire(v.at(3));

	REQUIRE(v.at(0)->get_is_loaded() == false);
	REQUIRE(v.at(2)->get_is_loaded() == true);
	REQUIRE(v.at(3)->get_is_loaded() == true);
}
<|endoftext|>


<commit_before>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "command.h"
#include "progressbar.h"
#include "image/buffer.h"
#include "image/voxel.h"
#include "image/axis.h"
#include "image/threaded_copy.h"
#include "image/adapter/extract.h"
#include "image/adapter/permute_axes.h"
#include "image/stride.h"
#include "dwi/gradient.h"

using namespace MR;
using namespace App;

void usage ()
{
  DESCRIPTION
  + "perform conversion between different file types and optionally "
  "extract a subset of the input image."

  + "If used correctly, this program can be a very useful workhorse. "
  "In addition to converting images between different formats, it can "
  "be used to extract specific studies from a data set, extract a "
  "specific region of interest, or flip the images.";

  ARGUMENTS
  + Argument ("input", "the input image.").type_image_in ()
  + Argument ("output", "the output image.").type_image_out ();

  OPTIONS
  + Option ("coord",
            "extract data from the input image only at the coordinates specified.")
  .allow_multiple()
  + Argument ("axis").type_integer (0, 0, std::numeric_limits<int>::max())
  + Argument ("coord").type_sequence_int()

  + Option ("vox",
            "change the voxel dimensions of the output image. The new sizes should "
            "be provided as a comma-separated list of values. Only those values "
            "specified will be changed. For example: 1,,3.5 will change the voxel "
            "size along the x & z axes, and leave the y-axis voxel size unchanged.")
  + Argument ("sizes").type_sequence_float()

  + Option ("axes",
            "specify the axes from the input image that will be used to form the output "
            "image. This allows the permutation, ommission, or addition of axes into the "
            "output image. The axes should be supplied as a comma-separated list of axes. "
            "Any ommitted axes must have dimension 1. Axes can be inserted by supplying "
            "-1 at the corresponding position in the list.")
  + Argument ("axes").type_sequence_int()

  + Image::Stride::StrideOption

  + DataType::options()

  + DWI::GradImportOptions (false)
  + DWI::GradExportOptions();
}

template <class InfoType>
inline std::vector<int> set_header (Image::Header& header, const InfoType& input)
{
  // need to preserve dataype, already parsed from command-line:
  auto datatype = header.datatype();
  header.info() = input.info();
  header.datatype() = datatype;

  if (get_options ("grad").size() || get_options ("fslgrad").size())
    header.DW_scheme() = DWI::get_DW_scheme<float> (header);

  Options opt = get_options ("axes");
  std::vector<int> axes;
  if (opt.size()) {
    axes = opt[0][0];
    header.set_ndim (axes.size());
    for (size_t i = 0; i < axes.size(); ++i) {
      if (axes[i] >= static_cast<int> (input.ndim()))
        throw Exception ("axis supplied to option -axes is out of bounds");
      header.dim(i) = axes[i] < 0 ? 1 : input.dim (axes[i]);
    }
  } else {
    header.set_ndim (input.ndim());
    axes.assign (input.ndim(), 0);
    for (size_t i = 0; i < axes.size(); ++i) {
      axes[i] = i;
      header.dim (i) = input.dim (i);
    }
  }

  opt = get_options ("vox");
  if (opt.size()) {
    std::vector<float> vox = opt[0][0];
    if (vox.size() > header.ndim())
      throw Exception ("too many axes supplied to -vox option");
    for (size_t n = 0; n < vox.size(); ++n) {
      if (std::isfinite (vox[n]))
        header.vox(n) = vox[n];
    }
  }

  Image::Stride::set_from_command_line (header);

  return axes;
}

template <typename T>
inline void copy_permute (Image::Header& header_in, Image::Header& header_out, const std::vector< std::vector<int> >& pos, const std::string& output_filename)
{
  typedef Image::Buffer<T> buffer_type;
  typedef typename buffer_type::voxel_type voxel_type;
  typedef Image::Adapter::Extract<voxel_type> extract_type;

  buffer_type buffer_in (header_in);
  voxel_type in = buffer_in.voxel();

  if (pos.empty()) {

    const std::vector<int> axes = set_header (header_out, in);
    buffer_type buffer_out (output_filename, header_out);
    voxel_type out = buffer_out.voxel();
    DWI::export_grad_commandline (buffer_out);

    Image::Adapter::PermuteAxes<voxel_type> perm (in, axes);
    Image::threaded_copy_with_progress (perm, out, 2);

  } else {

    extract_type extract (in, pos);
    const std::vector<int> axes = set_header (header_out, extract);
    buffer_type buffer_out (output_filename, header_out);
    voxel_type out = buffer_out.voxel();
    DWI::export_grad_commandline (buffer_out);

    Image::Adapter::PermuteAxes<extract_type> perm (extract, axes);
    Image::threaded_copy_with_progress (perm, out, 2);

  }

}

void run ()
{
  Image::Header header_in (argument[0]);

  Image::Header header_out (header_in);
  header_out.datatype() = DataType::from_command_line (header_out.datatype());
  header_out.set_intensity_scaling (header_in);

  if (header_in.datatype().is_complex() && !header_out.datatype().is_complex())
    WARN ("requested datatype is real but input datatype is complex - imaginary component will be ignored");

  Options opt = get_options ("coord");
  std::vector< std::vector<int> > pos;
  if (opt.size()) {
    pos.assign (header_in.ndim(), std::vector<int>());
    for (size_t n = 0; n < opt.size(); n++) {
      int axis = opt[n][0];
      if (axis >= (int)header_in.ndim())
        throw Exception ("axis " + str(axis) + " provided with -coord option is out of range of input image");
      if (pos[axis].size())
        throw Exception ("\"coord\" option specified twice for axis " + str (axis));
      pos[axis] = parse_ints (opt[n][1], header_in.dim(axis)-1);
      if (axis == 3 && header_in.DW_scheme().is_set()) {
        Math::Matrix<float>& grad (header_in.DW_scheme());
        if ((int)grad.rows() != header_in.dim(3)) {
          WARN ("Diffusion encoding of input file does not match number of image volumes; omitting gradient information from output image");
          header_out.DW_scheme().clear();
        }
        else {
          Math::Matrix<float> extract_grad (pos[3].size(), 4);
          for (size_t dir = 0; dir != pos[3].size(); ++dir)
            extract_grad.row(dir) = grad.row((pos[3])[dir]);
          header_out.DW_scheme() = extract_grad;
        }
      }
    }

    for (size_t n = 0; n < header_in.ndim(); ++n) {
      if (pos[n].empty()) {
        pos[n].resize (header_in.dim (n));
        for (size_t i = 0; i < pos[n].size(); i++)
          pos[n][i] = i;
      }
    }
  }

  switch (header_out.datatype()() & DataType::Type) {
    case DataType::Undefined: throw Exception ("Undefined output image data type"); break;
    case DataType::Bit:
    case DataType::UInt8:
    case DataType::UInt16:
    case DataType::UInt32:
      if (header_out.datatype().is_signed())
        copy_permute<int32_t> (header_in, header_out, pos, argument[1]);
      else
        copy_permute<uint32_t> (header_in, header_out, pos, argument[1]);
      break;
    case DataType::UInt64:
      if (header_out.datatype().is_signed())
        copy_permute<int64_t> (header_in, header_out, pos, argument[1]);
      else
        copy_permute<uint64_t> (header_in, header_out, pos, argument[1]);
      break;
    case DataType::Float32:
    case DataType::Float64:
      if (header_out.datatype().is_complex())
        copy_permute<cdouble> (header_in, header_out, pos, argument[1]);
      else
        copy_permute<double> (header_in, header_out, pos, argument[1]);
      break;
  }

}

<commit_msg>mrconvert: add -scaling option to control intensity scaling parameters<commit_after>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "command.h"
#include "progressbar.h"
#include "image/buffer.h"
#include "image/voxel.h"
#include "image/axis.h"
#include "image/threaded_copy.h"
#include "image/adapter/extract.h"
#include "image/adapter/permute_axes.h"
#include "image/stride.h"
#include "dwi/gradient.h"

using namespace MR;
using namespace App;

void usage ()
{
  DESCRIPTION
  + "perform conversion between different file types and optionally "
  "extract a subset of the input image."

  + "If used correctly, this program can be a very useful workhorse. "
  "In addition to converting images between different formats, it can "
  "be used to extract specific studies from a data set, extract a "
  "specific region of interest, or flip the images.";

  ARGUMENTS
  + Argument ("input", "the input image.").type_image_in ()
  + Argument ("output", "the output image.").type_image_out ();

  OPTIONS
  + Option ("coord",
            "extract data from the input image only at the coordinates specified.")
  .allow_multiple()
  + Argument ("axis").type_integer (0, 0, std::numeric_limits<int>::max())
  + Argument ("coord").type_sequence_int()

  + Option ("vox",
            "change the voxel dimensions of the output image. The new sizes should "
            "be provided as a comma-separated list of values. Only those values "
            "specified will be changed. For example: 1,,3.5 will change the voxel "
            "size along the x & z axes, and leave the y-axis voxel size unchanged.")
  + Argument ("sizes").type_sequence_float()

  + Option ("axes",
            "specify the axes from the input image that will be used to form the output "
            "image. This allows the permutation, ommission, or addition of axes into the "
            "output image. The axes should be supplied as a comma-separated list of axes. "
            "Any ommitted axes must have dimension 1. Axes can be inserted by supplying "
            "-1 at the corresponding position in the list.")
  + Argument ("axes").type_sequence_int()

  + Option ("scaling",
            "specify the data scaling parameters used to rescale the intensity values. "
            "These take the form of a comma-separated 2-vector of floating-point values, "
            "corresponding to offset & scale, with final intensity values being given by "
            "offset + scale * stored_value. By default, the values in the original header "
            "are preserved.")
  + Argument ("values").type_sequence_float()

  + Image::Stride::StrideOption

  + DataType::options()

  + DWI::GradImportOptions (false)
  + DWI::GradExportOptions();
}

template <class InfoType>
inline std::vector<int> set_header (Image::Header& header, const InfoType& input)
{
  // need to preserve dataype, already parsed from command-line:
  auto datatype = header.datatype();
  header.info() = input.info();
  header.datatype() = datatype;

  Options opt = get_options ("scaling");
  if (opt.size()) {
    std::vector<float> scaling = opt[0][0];
    if (scaling.size() != 2)
      throw Exception ("-scaling option expects comma-separated 2-vector of floating-point values");
    header.intensity_offset() = scaling[0];
    header.intensity_scale() = scaling[1];
  }

  if (get_options ("grad").size() || get_options ("fslgrad").size())
    header.DW_scheme() = DWI::get_DW_scheme<float> (header);

  opt = get_options ("axes");
  std::vector<int> axes;
  if (opt.size()) {
    axes = opt[0][0];
    header.set_ndim (axes.size());
    for (size_t i = 0; i < axes.size(); ++i) {
      if (axes[i] >= static_cast<int> (input.ndim()))
        throw Exception ("axis supplied to option -axes is out of bounds");
      header.dim(i) = axes[i] < 0 ? 1 : input.dim (axes[i]);
    }
  } else {
    header.set_ndim (input.ndim());
    axes.assign (input.ndim(), 0);
    for (size_t i = 0; i < axes.size(); ++i) {
      axes[i] = i;
      header.dim (i) = input.dim (i);
    }
  }

  opt = get_options ("vox");
  if (opt.size()) {
    std::vector<float> vox = opt[0][0];
    if (vox.size() > header.ndim())
      throw Exception ("too many axes supplied to -vox option");
    for (size_t n = 0; n < vox.size(); ++n) {
      if (std::isfinite (vox[n]))
        header.vox(n) = vox[n];
    }
  }

  Image::Stride::set_from_command_line (header);

  return axes;
}

template <typename T>
inline void copy_permute (Image::Header& header_in, Image::Header& header_out, const std::vector< std::vector<int> >& pos, const std::string& output_filename)
{
  typedef Image::Buffer<T> buffer_type;
  typedef typename buffer_type::voxel_type voxel_type;
  typedef Image::Adapter::Extract<voxel_type> extract_type;

  buffer_type buffer_in (header_in);
  voxel_type in = buffer_in.voxel();

  if (pos.empty()) {

    const std::vector<int> axes = set_header (header_out, in);
    buffer_type buffer_out (output_filename, header_out);
    voxel_type out = buffer_out.voxel();
    DWI::export_grad_commandline (buffer_out);

    Image::Adapter::PermuteAxes<voxel_type> perm (in, axes);
    Image::threaded_copy_with_progress (perm, out, 2);

  } else {

    extract_type extract (in, pos);
    const std::vector<int> axes = set_header (header_out, extract);
    buffer_type buffer_out (output_filename, header_out);
    voxel_type out = buffer_out.voxel();
    DWI::export_grad_commandline (buffer_out);

    Image::Adapter::PermuteAxes<extract_type> perm (extract, axes);
    Image::threaded_copy_with_progress (perm, out, 2);

  }

}

void run ()
{
  Image::Header header_in (argument[0]);

  Image::Header header_out (header_in);
  header_out.datatype() = DataType::from_command_line (header_out.datatype());
  header_out.set_intensity_scaling (header_in);

  if (header_in.datatype().is_complex() && !header_out.datatype().is_complex())
    WARN ("requested datatype is real but input datatype is complex - imaginary component will be ignored");

  Options opt = get_options ("coord");
  std::vector< std::vector<int> > pos;
  if (opt.size()) {
    pos.assign (header_in.ndim(), std::vector<int>());
    for (size_t n = 0; n < opt.size(); n++) {
      int axis = opt[n][0];
      if (axis >= (int)header_in.ndim())
        throw Exception ("axis " + str(axis) + " provided with -coord option is out of range of input image");
      if (pos[axis].size())
        throw Exception ("\"coord\" option specified twice for axis " + str (axis));
      pos[axis] = parse_ints (opt[n][1], header_in.dim(axis)-1);
      if (axis == 3 && header_in.DW_scheme().is_set()) {
        Math::Matrix<float>& grad (header_in.DW_scheme());
        if ((int)grad.rows() != header_in.dim(3)) {
          WARN ("Diffusion encoding of input file does not match number of image volumes; omitting gradient information from output image");
          header_out.DW_scheme().clear();
        }
        else {
          Math::Matrix<float> extract_grad (pos[3].size(), 4);
          for (size_t dir = 0; dir != pos[3].size(); ++dir)
            extract_grad.row(dir) = grad.row((pos[3])[dir]);
          header_out.DW_scheme() = extract_grad;
        }
      }
    }

    for (size_t n = 0; n < header_in.ndim(); ++n) {
      if (pos[n].empty()) {
        pos[n].resize (header_in.dim (n));
        for (size_t i = 0; i < pos[n].size(); i++)
          pos[n][i] = i;
      }
    }
  }

  switch (header_out.datatype()() & DataType::Type) {
    case DataType::Undefined: throw Exception ("Undefined output image data type"); break;
    case DataType::Bit:
    case DataType::UInt8:
    case DataType::UInt16:
    case DataType::UInt32:
      if (header_out.datatype().is_signed())
        copy_permute<int32_t> (header_in, header_out, pos, argument[1]);
      else
        copy_permute<uint32_t> (header_in, header_out, pos, argument[1]);
      break;
    case DataType::UInt64:
      if (header_out.datatype().is_signed())
        copy_permute<int64_t> (header_in, header_out, pos, argument[1]);
      else
        copy_permute<uint64_t> (header_in, header_out, pos, argument[1]);
      break;
    case DataType::Float32:
    case DataType::Float64:
      if (header_out.datatype().is_complex())
        copy_permute<cdouble> (header_in, header_out, pos, argument[1]);
      else
        copy_permute<double> (header_in, header_out, pos, argument[1]);
      break;
  }

}

<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <MLOpen.h>
#include <CL/cl.h>
#include <vector>
// #include "mloConvHost.hpp"

void failed(const char * msg, const char* file, int line)
{
    printf("FAILED: %s: %s:%i\n", msg, file, line);
    std::abort();
}

#define CHECK(...) if (!(__VA_ARGS__)) failed(#__VA_ARGS__, __FILE__, __LINE__)

struct handle_fixture
{
    mlopenHandle_t handle;
    cl_command_queue q;

    handle_fixture()
    {
        mlopenCreate(&handle);
        mlopenGetStream(handle, &q);
    }

    ~handle_fixture()
    {
        mlopenDestroy(handle);
    }
};

struct input_tensor_fixture : virtual handle_fixture
{
    mlopenTensorDescriptor_t inputTensor;

    input_tensor_fixture()
    {
        mlopenCreateTensorDescriptor(handle, &inputTensor);
        mlopenInit4dTensorDescriptor(handle,
                inputTensor,
                mlopenFloat,
                100,
                32,
                8,
                8);

    }

    ~input_tensor_fixture()
    {
        mlopenDestroyTensorDescriptor(inputTensor);
    }

    void run()
    {
        int n, c, h, w;
        int nStride, cStride, hStride, wStride;
        mlopenDataType_t dt;

        mlopenGet4dTensorDescriptor(handle,
                inputTensor,
                &dt,
                &n,
                &c,
                &h,
                &w,
                &nStride,
                &cStride,
                &hStride,
                &wStride);

        CHECK(dt == 1);
        CHECK(n == 100);
        CHECK(c == 32);
        CHECK(h == 8);
        CHECK(w == 8);
        CHECK(nStride == 1);
        CHECK(cStride == 1);
        CHECK(hStride == 1);
        CHECK(wStride == 1);
    }
};

struct conv_filter_fixture : virtual handle_fixture
{
    mlopenTensorDescriptor_t convFilter;
    mlopenConvolutionDescriptor_t convDesc;

    static const mlopenConvolutionMode_t mode = mlopenConvolution;

    conv_filter_fixture()
    {
        mlopenCreateTensorDescriptor(handle, &convFilter);
        // weights
        mlopenInit4dTensorDescriptor(handle,
            convFilter,
            mlopenFloat,
            64,  // outputs
            32,   // inputs
            5,   // kernel size
            5);

        mlopenCreateConvolutionDescriptor(handle, &convDesc);
        // convolution with padding 2
        mlopenInitConvolutionDescriptor(convDesc,
                mode,
                2,
                2,
                1,
                1,
                1,
                1);

    }
    ~conv_filter_fixture()
    {
        mlopenDestroyTensorDescriptor(convFilter);
        mlopenDestroyConvolutionDescriptor(convDesc);
    }

    void run()
    {
        // TODO: Update API to not require mode by pointer
        mlopenConvolutionMode_t lmode = mode;
        int pad_w, pad_h, u, v, upx, upy;
        mlopenGetConvolutionDescriptor(convDesc,
                &lmode,
                &pad_h, &pad_w, &u, &v,
                &upx, &upy);

        CHECK(mode == 0);
        CHECK(pad_h == 2);
        CHECK(pad_w == 2);
        CHECK(u == 1);
        CHECK(v == 1);
        CHECK(upx == 1);
        CHECK(upy == 1);
    }
};

struct output_tensor_fixture : conv_filter_fixture, input_tensor_fixture
{
    mlopenTensorDescriptor_t outputTensor;
    output_tensor_fixture()
    {
        int x, y, z, a;
        mlopenGetConvolutionForwardOutputDim(convDesc, inputTensor, convFilter, &x, &y, &z, &a);

        mlopenCreateTensorDescriptor(handle, &outputTensor);

        mlopenInit4dTensorDescriptor(handle,
            outputTensor,
            mlopenFloat,
            x,
            y,
            z,
            a);
    }
    ~output_tensor_fixture()
    {
        mlopenDestroyTensorDescriptor(outputTensor);
    }

    void run()
    {
        int x, y, z, a;
        mlopenGetConvolutionForwardOutputDim(convDesc, inputTensor, convFilter, &x, &y, &z, &a);

        CHECK(x == 100);
        CHECK(y == 64);
        CHECK(z == 8);
        CHECK(a == 8);
    }
};

struct conv_forward : output_tensor_fixture
{
    void run()
    {
        int alpha = 1, beta = 1;
        mlopenTransformTensor(handle,
                &alpha,
                inputTensor,
                NULL,
                &beta,
                convFilter,
                NULL);

        int value = 10;
        mlopenSetTensor(handle, inputTensor, NULL, &value);

        mlopenScaleTensor(handle, inputTensor, NULL, &alpha);

        // Setup OpenCL buffers

        cl_int status;
        const int sz = 1024;
        std::vector<float> a1(sz, 1.0);
        std::vector<float> b1(sz, 6.0);
        std::vector<float> c1(sz, 0.0);

        cl_context ctx;
        clGetCommandQueueInfo(q, CL_QUEUE_CONTEXT, sizeof(cl_context), &ctx, NULL);

        cl_mem adev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz,NULL, &status);
        CHECK(status == CL_SUCCESS);

        cl_mem bdev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz,NULL, NULL);
        cl_mem cdev = clCreateBuffer(ctx, CL_MEM_READ_WRITE, 4*sz,NULL, NULL);

        status = clEnqueueWriteBuffer(q, adev, CL_TRUE, 0, 4*sz, a1.data(), 0, NULL, NULL);
        status |= clEnqueueWriteBuffer(q, bdev, CL_TRUE, 0, 4*sz, b1.data(), 0, NULL, NULL);
        status |= clEnqueueWriteBuffer(q, cdev, CL_TRUE, 0, 4*sz, c1.data(), 0, NULL, NULL);
        CHECK(status == CL_SUCCESS);

        int ret_algo_count;
        mlopenConvAlgoPerf_t perf;

        mlopenFindConvolutionForwardAlgorithm(handle,
            inputTensor,
            adev,
            convFilter,
            bdev,
            convDesc,
            outputTensor,
            cdev,
            1,
            &ret_algo_count,
            &perf,
            mlopenConvolutionFastest,
            NULL,
            10);

        mlopenConvolutionForward(handle,
            &alpha,
            inputTensor,
            NULL,
            convFilter,
            NULL,
            convDesc,
            mlopenConvolutionFwdAlgoDirect,
            &beta,
            outputTensor,
            NULL);
    }
};

int main() {
    input_tensor_fixture{}.run();
    conv_filter_fixture{}.run();
    output_tensor_fixture{}.run();
    conv_forward{}.run();
}

<commit_msg>Fix tests with update paramters<commit_after>#include <iostream>
#include <cstdio>
#include <MLOpen.h>
#include <CL/cl.h>
#include <vector>
// #include "mloConvHost.hpp"

void failed(const char * msg, const char* file, int line)
{
    printf("FAILED: %s: %s:%i\n", msg, file, line);
    std::abort();
}

#define CHECK(...) if (!(__VA_ARGS__)) failed(#__VA_ARGS__, __FILE__, __LINE__)

struct handle_fixture
{
    mlopenHandle_t handle;
    cl_command_queue q;

    handle_fixture()
    {
        mlopenCreate(&handle);
        mlopenGetStream(handle, &q);
    }

    ~handle_fixture()
    {
        mlopenDestroy(handle);
    }
};

struct input_tensor_fixture : virtual handle_fixture
{
    mlopenTensorDescriptor_t inputTensor;

    input_tensor_fixture()
    {
        mlopenCreateTensorDescriptor(handle, &inputTensor);
        mlopenInit4dTensorDescriptor(handle,
                inputTensor,
                mlopenFloat,
                100,
                32,
                8,
                8);

    }

    ~input_tensor_fixture()
    {
        mlopenDestroyTensorDescriptor(inputTensor);
    }

    void run()
    {
        int n, c, h, w;
        int nStride, cStride, hStride, wStride;
        mlopenDataType_t dt;

        mlopenGet4dTensorDescriptor(handle,
                inputTensor,
                &dt,
                &n,
                &c,
                &h,
                &w,
                &nStride,
                &cStride,
                &hStride,
                &wStride);

        CHECK(dt == 1);
        CHECK(n == 100);
        CHECK(c == 32);
        CHECK(h == 8);
        CHECK(w == 8);
        CHECK(nStride == 1);
        CHECK(cStride == 1);
        CHECK(hStride == 1);
        CHECK(wStride == 1);
    }
};

struct conv_filter_fixture : virtual handle_fixture
{
    mlopenTensorDescriptor_t convFilter;
    mlopenConvolutionDescriptor_t convDesc;

    static const mlopenConvolutionMode_t mode = mlopenConvolution;

    conv_filter_fixture()
    {
        mlopenCreateTensorDescriptor(handle, &convFilter);
        // weights
        mlopenInit4dTensorDescriptor(handle,
            convFilter,
            mlopenFloat,
            64,  // outputs
            32,   // inputs
            5,   // kernel size
            5);

        mlopenCreateConvolutionDescriptor(handle, &convDesc);
        // convolution with padding 2
        mlopenInitConvolutionDescriptor(convDesc,
                mode,
                2,
                2,
                1,
                1,
                1,
                1);

    }
    ~conv_filter_fixture()
    {
        mlopenDestroyTensorDescriptor(convFilter);
        mlopenDestroyConvolutionDescriptor(convDesc);
    }

    void run()
    {
        // TODO: Update API to not require mode by pointer
        mlopenConvolutionMode_t lmode = mode;
        int pad_w, pad_h, u, v, upx, upy;
        mlopenGetConvolutionDescriptor(convDesc,
                &lmode,
                &pad_h, &pad_w, &u, &v,
                &upx, &upy);

        CHECK(mode == 0);
        CHECK(pad_h == 2);
        CHECK(pad_w == 2);
        CHECK(u == 1);
        CHECK(v == 1);
        CHECK(upx == 1);
        CHECK(upy == 1);
    }
};

struct output_tensor_fixture : conv_filter_fixture, input_tensor_fixture
{
    mlopenTensorDescriptor_t outputTensor;
    output_tensor_fixture()
    {
        int x, y, z, a;
        mlopenGetConvolutionForwardOutputDim(convDesc, inputTensor, convFilter, &x, &y, &z, &a);

        mlopenCreateTensorDescriptor(handle, &outputTensor);

        mlopenInit4dTensorDescriptor(handle,
            outputTensor,
            mlopenFloat,
            x,
            y,
            z,
            a);
    }
    ~output_tensor_fixture()
    {
        mlopenDestroyTensorDescriptor(outputTensor);
    }

    void run()
    {
        int x, y, z, a;
        mlopenGetConvolutionForwardOutputDim(convDesc, inputTensor, convFilter, &x, &y, &z, &a);

        CHECK(x == 100);
        CHECK(y == 64);
        CHECK(z == 8);
        CHECK(a == 8);
    }
};

struct conv_forward : output_tensor_fixture
{
    void run()
    {
        int alpha = 1, beta = 1;
        mlopenTransformTensor(handle,
                &alpha,
                inputTensor,
                NULL,
                &beta,
                convFilter,
                NULL);

        int value = 10;
        mlopenSetTensor(handle, inputTensor, NULL, &value);

        mlopenScaleTensor(handle, inputTensor, NULL, &alpha);

        // Setup OpenCL buffers

        cl_int status;
        const int sz = 1024;
        std::vector<float> a1(sz, 1.0);
        std::vector<float> b1(sz, 6.0);
        std::vector<float> c1(sz, 0.0);

        cl_context ctx;
        clGetCommandQueueInfo(q, CL_QUEUE_CONTEXT, sizeof(cl_context), &ctx, NULL);

        cl_mem adev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz,NULL, &status);
        CHECK(status == CL_SUCCESS);

        cl_mem bdev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz,NULL, NULL);
        cl_mem cdev = clCreateBuffer(ctx, CL_MEM_READ_WRITE, 4*sz,NULL, NULL);

        status = clEnqueueWriteBuffer(q, adev, CL_TRUE, 0, 4*sz, a1.data(), 0, NULL, NULL);
        status |= clEnqueueWriteBuffer(q, bdev, CL_TRUE, 0, 4*sz, b1.data(), 0, NULL, NULL);
        status |= clEnqueueWriteBuffer(q, cdev, CL_TRUE, 0, 4*sz, c1.data(), 0, NULL, NULL);
        CHECK(status == CL_SUCCESS);

        int ret_algo_count;
        mlopenConvAlgoPerf_t perf;

        mlopenFindConvolutionForwardAlgorithm(handle,
            inputTensor,
            adev,
            convFilter,
            bdev,
            convDesc,
            outputTensor,
            cdev,
            1,
            &ret_algo_count,
            &perf,
            mlopenConvolutionFastest,
            NULL,
            10);

        mlopenConvolutionForward(handle,
            &alpha,
            inputTensor,
            NULL,
            convFilter,
            NULL,
            convDesc,
            mlopenConvolutionFwdAlgoDirect,
            &beta,
            outputTensor,
            NULL,
            NULL,
            0);
    }
};

int main() {
    input_tensor_fixture{}.run();
    conv_filter_fixture{}.run();
    output_tensor_fixture{}.run();
    conv_forward{}.run();
}

<|endoftext|>