/*
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * For use for simulation and test purposes only
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Tuan Ta
 */

#include "cpu/testers/gpu_ruby_test/Episode.hh"

#include <fstream>
#include <unordered_set>

#include "cpu/testers/gpu_ruby_test/ProtocolTester.hh"
#include "cpu/testers/gpu_ruby_test/Thread.hh"

Episode::Episode(ProtocolTester* _tester, Thread* _thread, int num_loads,
                 int num_stores)
      : tester(_tester),
        thread(_thread),
        numLoads(num_loads),
        numStores(num_stores),
        nextActionIdx(0)
{
    assert(tester && thread);

    episodeId = tester->getNextEpisodeID();
    numLanes = thread->getNumLanes();
    assert(numLanes > 0);

    addrManager = tester->getAddressManager();
    assert(addrManager);

    atomicLocs.resize(numLanes, AddressManager::INVALID_LOCATION);
    // generate a sequence of actions
    initActions();
    isActive = true;

    DPRINTFN("Episode %d\n", episodeId);
}

Episode::~Episode()
{
    for (Episode::Action* action : actions) {
        assert(action);
        delete action;
    }
}

const Episode::Action*
Episode::peekCurAction() const
{
    if (nextActionIdx < actions.size())
        return actions[nextActionIdx];
    else
        return nullptr;
}

void
Episode::popAction()
{
    assert(nextActionIdx < actions.size());
    nextActionIdx++;
}

void
Episode::initActions()
{
    // first, push Atomic & then Acquire action
    actions.push_back(new Action(Action::Type::ATOMIC, numLanes));
    actions.push_back(new Action(Action::Type::ACQUIRE, numLanes));

    // second, push a number of LD/ST actions
    int num_loads = numLoads;
    int num_stores = numStores;
    while ((num_loads + num_stores) > 0) {
        switch (random() % 2) {
            case 0: // Load
                if (num_loads > 0) {
                    actions.push_back(new Action(Action::Type::LOAD,
                                                   numLanes));
                    num_loads--;
                }
                break;
            case 1: // Store
                if (num_stores > 0) {
                    actions.push_back(new Action(Action::Type::STORE,
                                                   numLanes));
                    num_stores--;
                }
                break;
            default:
                assert(false);
        }
    }

    // last, push an Release & then Atomic action
    actions.push_back(new Action(Action::Type::RELEASE, numLanes));
    actions.push_back(new Action(Action::Type::ATOMIC, numLanes));

    // for each lane, pick a list of locations
    Location normal_loc;

    for (int lane = 0; lane < numLanes; ++lane) {
        normal_loc = AddressManager::INVALID_LOCATION;

        // first, we select atomic loc for this lane
        // atomic loc for this lane should not have been picked yet
        assert(atomicLocs[lane] == AddressManager::INVALID_LOCATION);
        // pick randomly an atomic location
        atomicLocs[lane] = addrManager->getAtomicLoc();
        assert(atomicLocs[lane] >= 0);

        // go through each action in this lane and set its location
        for (Action* action : actions) {
            assert(action);

            switch (action->getType()) {
                case Action::Type::ATOMIC:
                    action->setLocation(lane, atomicLocs[lane]);
                    break;
                case Action::Type::LOAD:
                    // pick randomly a normal location
                    normal_loc = addrManager->
                                            getLoadLoc(atomicLocs[lane]);
                    assert(normal_loc >= AddressManager::INVALID_LOCATION);

                    if (normal_loc != AddressManager::INVALID_LOCATION) {
                        // check DRF
                        if (!tester->checkDRF(atomicLocs[lane],
                                                normal_loc, false) ||
                            !this->checkDRF(atomicLocs[lane], normal_loc,
                                            false, lane)) {
                            panic("Thread %d - Data race detected. STOPPED!\n",
                                  thread->getThreadId());
                        }
                    }

                    action->setLocation(lane, normal_loc);
                    break;
                case Action::Type::STORE:
                    // pick randomly a normal location
                    normal_loc = addrManager->
                                            getStoreLoc(atomicLocs[lane]);
                    assert(normal_loc >= AddressManager::INVALID_LOCATION);

                    if (normal_loc != AddressManager::INVALID_LOCATION) {
                        // check DRF
                        if (!tester->checkDRF(atomicLocs[lane],
                                                normal_loc, true) ||
                            !this->checkDRF(atomicLocs[lane], normal_loc,
                                            true, lane)) {
                            panic("Thread %d - Data race detected. STOPPED!\n",
                                  thread->getThreadId());
                        }
                    }

                    action->setLocation(lane, normal_loc);
                    break;
                case Action::Type::ACQUIRE:
                case Action::Type::RELEASE:
                    // no op
                    break;
                default:
                    panic("Invalid action type\n");
            }
        }

        addrManager->finishLocSelection(atomicLocs[lane]);
    }
}

void
Episode::completeEpisode()
{
    // release all locations this episode has picked and used
    Location atomic_loc, normal_loc;
    for (int lane = 0; lane < numLanes; ++lane) {
        atomic_loc = AddressManager::INVALID_LOCATION;
        normal_loc = AddressManager::INVALID_LOCATION;

        std::unordered_set<Location> unique_loc_set;

        for (Action* action : actions) {
            assert(action);

            if (action->isAtomicAction()) {
                if (atomic_loc == AddressManager::INVALID_LOCATION) {
                    atomic_loc = action->getLocation(lane);
                } else {
                    // both atomic ops in the same lane must be
                    // at the same location
                    assert(atomic_loc == action->getLocation(lane));
                }
            } else if (!action->isMemFenceAction()) {
                assert(atomic_loc >= 0);
                normal_loc = action->getLocation(lane);

                if (normal_loc >= 0)
                    unique_loc_set.insert(normal_loc);
            }
        }

        // each unique loc can be released only once
        for (Location loc : unique_loc_set)
            addrManager->releaseLocation(atomic_loc, loc);
    }

    // this episode is no longer active
    isActive = false;
}

bool
Episode::checkDRF(Location atomic_loc, Location loc, bool isStore,
                  int max_lane) const
{
    assert(atomic_loc != AddressManager::INVALID_LOCATION);
    assert(loc != AddressManager::INVALID_LOCATION);
    assert(max_lane <= numLanes);

    for (int lane = 0; lane < max_lane; ++lane) {
        if (atomic_loc == atomicLocs[lane]) {
            for (const Action* action : actions) {
                if (!action->isAtomicAction() &&
                    !action->isMemFenceAction()) {
                    if (isStore && loc == action->getLocation(lane)) {
                        warn("ST at location %d races against thread %d\n",
                             loc, thread->getThreadId());
                        return false;
                    } else if (!isStore &&
                               action->getType() == Action::Type::STORE &&
                               loc == action->getLocation(lane)) {
                        warn("LD at location %d races against thread %d\n",
                             loc, thread->getThreadId());
                        return false;
                    }
                }
            }
        }
    }

    return true;
}

// -------------------- Action class ----------------------------
Episode::Action::Action(Type t, int num_lanes)
    : type(t),
      numLanes(num_lanes)
{
    assert(numLanes > 0);
    locations.resize(numLanes);
    for (Location &loc : locations) loc = AddressManager::INVALID_LOCATION;
}

void
Episode::Action::setLocation(int lane, Location loc)
{
    assert(lane >= 0 && lane < numLanes);
    locations[lane] = loc;
}

AddressManager::Location
Episode::Action::getLocation(int lane) const
{
    assert(lane >= 0 && lane < numLanes);
    return locations[lane];
}

bool
Episode::Action::isAtomicAction() const
{
    return (type == Type::ATOMIC);
}

bool
Episode::Action::isMemFenceAction() const
{
    return (type == Type::ACQUIRE || type == Type::RELEASE);
}

const std::string
Episode::Action::printType() const
{
    if (type == Type::ACQUIRE)
        return "ACQUIRE";
    else if (type == Type::RELEASE)
        return "RELEASE";
    else if (type == Type::ATOMIC)
        return "ATOMIC";
    else if (type == Type::LOAD)
        return "LOAD";
    else if (type == Type::STORE)
        return "STORE";
    else
        panic("Invalid action type\n");
}
