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

#include "large_object_space.h"

#include "base/time_utils.h"
#include "space_test.h"

namespace art {
namespace gc {
namespace space {

class LargeObjectSpaceTest : public SpaceTest<CommonRuntimeTest> {
 public:
  void LargeObjectTest();

  static constexpr size_t kNumThreads = 10;
  static constexpr size_t kNumIterations = 1000;
  void RaceTest();
};


void LargeObjectSpaceTest::LargeObjectTest() {
  size_t rand_seed = 0;
  Thread* const self = Thread::Current();
  for (size_t i = 0; i < 2; ++i) {
    LargeObjectSpace* los = nullptr;
    const size_t capacity = 128 * MB;
    if (i == 0) {
      los = space::LargeObjectMapSpace::Create("large object space");
    } else {
      los = space::FreeListSpace::Create("large object space", capacity);
    }

    // Make sure the bitmap is not empty and actually covers at least how much we expect.
    CHECK_LT(static_cast<uintptr_t>(los->GetLiveBitmap()->HeapBegin()),
             static_cast<uintptr_t>(los->GetLiveBitmap()->HeapLimit()));
    CHECK_LE(static_cast<uintptr_t>(los->GetLiveBitmap()->HeapBegin() + capacity),
             static_cast<uintptr_t>(los->GetLiveBitmap()->HeapLimit()));

    static const size_t num_allocations = 64;
    static const size_t max_allocation_size = 0x100000;
    std::vector<std::pair<mirror::Object*, size_t>> requests;

    for (size_t phase = 0; phase < 2; ++phase) {
      while (requests.size() < num_allocations) {
        size_t request_size = test_rand(&rand_seed) % max_allocation_size;
        size_t allocation_size = 0;
        size_t bytes_tl_bulk_allocated;
        mirror::Object* obj = los->Alloc(self, request_size, &allocation_size, nullptr,
                                         &bytes_tl_bulk_allocated);
        ASSERT_TRUE(obj != nullptr);
        ASSERT_EQ(allocation_size, los->AllocationSize(obj, nullptr));
        ASSERT_GE(allocation_size, request_size);
        ASSERT_EQ(allocation_size, bytes_tl_bulk_allocated);
        // Fill in our magic value.
        uint8_t magic = (request_size & 0xFF) | 1;
        memset(obj, magic, request_size);
        requests.push_back(std::make_pair(obj, request_size));
      }

      // "Randomly" shuffle the requests.
      for (size_t k = 0; k < 10; ++k) {
        for (size_t j = 0; j < requests.size(); ++j) {
          std::swap(requests[j], requests[test_rand(&rand_seed) % requests.size()]);
        }
      }

      // Check the zygote flag for the first phase.
      if (phase == 0) {
        for (const auto& pair : requests) {
          mirror::Object* obj = pair.first;
          ASSERT_FALSE(los->IsZygoteLargeObject(self, obj));
        }
        los->SetAllLargeObjectsAsZygoteObjects(self);
        for (const auto& pair : requests) {
          mirror::Object* obj = pair.first;
          ASSERT_TRUE(los->IsZygoteLargeObject(self, obj));
        }
      }

      // Free 1 / 2 the allocations the first phase, and all the second phase.
      size_t limit = phase == 0 ? requests.size() / 2 : 0;
      while (requests.size() > limit) {
        mirror::Object* obj = requests.back().first;
        size_t request_size = requests.back().second;
        requests.pop_back();
        uint8_t magic = (request_size & 0xFF) | 1;
        for (size_t k = 0; k < request_size; ++k) {
          ASSERT_EQ(reinterpret_cast<const uint8_t*>(obj)[k], magic);
        }
        ASSERT_GE(los->Free(Thread::Current(), obj), request_size);
      }
    }
    // Test that dump doesn't crash.
    std::ostringstream oss;
    los->Dump(oss);
    LOG(INFO) << oss.str();

    size_t bytes_allocated = 0, bytes_tl_bulk_allocated;
    // Checks that the coalescing works.
    mirror::Object* obj = los->Alloc(self, 100 * MB, &bytes_allocated, nullptr,
                                     &bytes_tl_bulk_allocated);
    EXPECT_TRUE(obj != nullptr);
    los->Free(Thread::Current(), obj);

    EXPECT_EQ(0U, los->GetBytesAllocated());
    EXPECT_EQ(0U, los->GetObjectsAllocated());
    delete los;
  }
}

class AllocRaceTask : public Task {
 public:
  AllocRaceTask(size_t id, size_t iterations, size_t size, LargeObjectSpace* los) :
    id_(id), iterations_(iterations), size_(size), los_(los) {}

  void Run(Thread* self) override {
    for (size_t i = 0; i < iterations_ ; ++i) {
      size_t alloc_size, bytes_tl_bulk_allocated;
      mirror::Object* ptr = los_->Alloc(self, size_, &alloc_size, nullptr,
                                        &bytes_tl_bulk_allocated);

      NanoSleep((id_ + 3) * 1000);  // (3+id) mu s

      los_->Free(self, ptr);
    }
  }

  void Finalize() override {
    delete this;
  }

 private:
  size_t id_;
  size_t iterations_;
  size_t size_;
  LargeObjectSpace* los_;
};

void LargeObjectSpaceTest::RaceTest() {
  for (size_t los_type = 0; los_type < 2; ++los_type) {
    LargeObjectSpace* los = nullptr;
    if (los_type == 0) {
      los = space::LargeObjectMapSpace::Create("large object space");
    } else {
      los = space::FreeListSpace::Create("large object space", 128 * MB);
    }

    Thread* self = Thread::Current();
    ThreadPool thread_pool("Large object space test thread pool", kNumThreads);
    for (size_t i = 0; i < kNumThreads; ++i) {
      thread_pool.AddTask(self, new AllocRaceTask(i, kNumIterations, 16 * KB, los));
    }

    thread_pool.StartWorkers(self);

    thread_pool.Wait(self, true, false);

    delete los;
  }
}

TEST_F(LargeObjectSpaceTest, LargeObjectTest) {
  LargeObjectTest();
}

TEST_F(LargeObjectSpaceTest, RaceTest) {
  RaceTest();
}

}  // namespace space
}  // namespace gc
}  // namespace art
