blob: 008521754642af396d29c0e867ac0059a9e3f663 [file] [log] [blame]
/*
* Copyright (C) 2018 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 <iostream>
#include <gtest/gtest.h>
#include <stdlib.h>
#include "fifo/FifoBuffer.h"
#include "fifo/FifoController.h"
using android::fifo_frames_t;
using android::FifoController;
using android::FifoBuffer;
using android::WrappingBuffer;
//void foo() {
TEST(test_fifi_controller, fifo_indices) {
// Values are arbitrary primes designed to trigger edge cases.
constexpr int capacity = 83;
constexpr int threshold = 47;
FifoController fifoController(capacity, threshold);
ASSERT_EQ(capacity, fifoController.getCapacity());
ASSERT_EQ(threshold, fifoController.getThreshold());
ASSERT_EQ(0, fifoController.getReadCounter());
ASSERT_EQ(0, fifoController.getWriteCounter());
ASSERT_EQ(0, fifoController.getFullFramesAvailable());
ASSERT_EQ(threshold, fifoController.getEmptyFramesAvailable());
// Pretend to write some data.
constexpr int advance1 = 23;
fifoController.advanceWriteIndex(advance1);
int advanced = advance1;
ASSERT_EQ(0, fifoController.getReadCounter());
ASSERT_EQ(0, fifoController.getReadIndex());
ASSERT_EQ(advanced, fifoController.getWriteCounter());
ASSERT_EQ(advanced, fifoController.getWriteIndex());
ASSERT_EQ(advanced, fifoController.getFullFramesAvailable());
ASSERT_EQ(threshold - advanced, fifoController.getEmptyFramesAvailable());
// Pretend to read the data.
fifoController.advanceReadIndex(advance1);
ASSERT_EQ(advanced, fifoController.getReadCounter());
ASSERT_EQ(advanced, fifoController.getReadIndex());
ASSERT_EQ(advanced, fifoController.getWriteCounter());
ASSERT_EQ(advanced, fifoController.getWriteIndex());
ASSERT_EQ(0, fifoController.getFullFramesAvailable());
ASSERT_EQ(threshold, fifoController.getEmptyFramesAvailable());
// Write past end of buffer.
constexpr int advance2 = 13 + capacity - advance1;
fifoController.advanceWriteIndex(advance2);
advanced += advance2;
ASSERT_EQ(advance1, fifoController.getReadCounter());
ASSERT_EQ(advance1, fifoController.getReadIndex());
ASSERT_EQ(advanced, fifoController.getWriteCounter());
ASSERT_EQ(advanced - capacity, fifoController.getWriteIndex());
ASSERT_EQ(advance2, fifoController.getFullFramesAvailable());
ASSERT_EQ(threshold - advance2, fifoController.getEmptyFramesAvailable());
}
// TODO consider using a template for other data types.
class TestFifoBuffer {
public:
explicit TestFifoBuffer(fifo_frames_t capacity, fifo_frames_t threshold = 0)
: mFifoBuffer(sizeof(int16_t), capacity) {
// For reading and writing.
mData = new int16_t[capacity];
if (threshold <= 0) {
threshold = capacity;
}
mFifoBuffer.setThreshold(threshold);
mThreshold = threshold;
}
void checkMisc() {
ASSERT_EQ((int32_t)(2 * sizeof(int16_t)), mFifoBuffer.convertFramesToBytes(2));
ASSERT_EQ(mThreshold, mFifoBuffer.getThreshold());
}
// Verify that the available frames in each part add up correctly.
void checkWrappingBuffer() {
WrappingBuffer wrappingBuffer;
fifo_frames_t framesAvailable =
mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
fifo_frames_t wrapAvailable = mFifoBuffer.getEmptyRoomAvailable(&wrappingBuffer);
EXPECT_EQ(framesAvailable, wrapAvailable);
fifo_frames_t bothAvailable = wrappingBuffer.numFrames[0] + wrappingBuffer.numFrames[1];
EXPECT_EQ(framesAvailable, bothAvailable);
framesAvailable =
mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
wrapAvailable = mFifoBuffer.getFullDataAvailable(&wrappingBuffer);
EXPECT_EQ(framesAvailable, wrapAvailable);
bothAvailable = wrappingBuffer.numFrames[0] + wrappingBuffer.numFrames[1];
EXPECT_EQ(framesAvailable, bothAvailable);
}
// Write data but do not overflow.
void writeData(fifo_frames_t numFrames) {
fifo_frames_t framesAvailable =
mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
fifo_frames_t framesToWrite = std::min(framesAvailable, numFrames);
for (int i = 0; i < framesToWrite; i++) {
mData[i] = mNextWriteIndex++;
}
fifo_frames_t actual = mFifoBuffer.write(mData, framesToWrite);
ASSERT_EQ(framesToWrite, actual);
}
// Read data but do not underflow.
void verifyData(fifo_frames_t numFrames) {
fifo_frames_t framesAvailable =
mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
fifo_frames_t framesToRead = std::min(framesAvailable, numFrames);
fifo_frames_t actual = mFifoBuffer.read(mData, framesToRead);
ASSERT_EQ(framesToRead, actual);
for (int i = 0; i < framesToRead; i++) {
ASSERT_EQ(mNextVerifyIndex++, mData[i]);
}
}
// Wrap around the end of the buffer.
void checkWrappingWriteRead() {
constexpr int frames1 = 43;
constexpr int frames2 = 15;
writeData(frames1);
checkWrappingBuffer();
verifyData(frames1);
checkWrappingBuffer();
writeData(frames2);
checkWrappingBuffer();
verifyData(frames2);
checkWrappingBuffer();
}
// Write and Read a specific amount of data.
void checkWriteRead() {
const fifo_frames_t capacity = mFifoBuffer.getBufferCapacityInFrames();
// Wrap around with the smaller region in the second half.
const int frames1 = capacity - 4;
const int frames2 = 7; // arbitrary, small
writeData(frames1);
verifyData(frames1);
writeData(frames2);
verifyData(frames2);
}
// Write and Read a specific amount of data.
void checkWriteReadSmallLarge() {
const fifo_frames_t capacity = mFifoBuffer.getBufferCapacityInFrames();
// Wrap around with the larger region in the second half.
const int frames1 = capacity - 4;
const int frames2 = capacity - 9; // arbitrary, large
writeData(frames1);
verifyData(frames1);
writeData(frames2);
verifyData(frames2);
}
// Randomly read or write up to the maximum amount of data.
void checkRandomWriteRead() {
for (int i = 0; i < 20; i++) {
fifo_frames_t framesEmpty =
mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
fifo_frames_t numFrames = (fifo_frames_t)(drand48() * framesEmpty);
writeData(numFrames);
fifo_frames_t framesFull =
mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
numFrames = (fifo_frames_t)(drand48() * framesFull);
verifyData(numFrames);
}
}
FifoBuffer mFifoBuffer;
int16_t *mData;
fifo_frames_t mNextWriteIndex = 0;
fifo_frames_t mNextVerifyIndex = 0;
fifo_frames_t mThreshold;
};
TEST(test_fifo_buffer, fifo_read_write) {
constexpr int capacity = 51; // arbitrary
TestFifoBuffer tester(capacity);
tester.checkMisc();
tester.checkWriteRead();
}
TEST(test_fifo_buffer, fifo_wrapping_read_write) {
constexpr int capacity = 59; // arbitrary, a little bigger this time
TestFifoBuffer tester(capacity);
tester.checkWrappingWriteRead();
}
TEST(test_fifo_buffer, fifo_read_write_small_large) {
constexpr int capacity = 51; // arbitrary
TestFifoBuffer tester(capacity);
tester.checkWriteReadSmallLarge();
}
TEST(test_fifo_buffer, fifo_random_read_write) {
constexpr int capacity = 51; // arbitrary
TestFifoBuffer tester(capacity);
tester.checkRandomWriteRead();
}
TEST(test_fifo_buffer, fifo_random_threshold) {
constexpr int capacity = 67; // arbitrary
constexpr int threshold = 37; // arbitrary
TestFifoBuffer tester(capacity, threshold);
tester.checkRandomWriteRead();
}