/*
* Copyright Likewise Software
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library 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 Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
/*
* Authors: Brian Koropoff (bkoropoff@likewise.com)
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "benchmark.h"
#define MU_ASSERT_STATUS_SUCCESS(status) \
MU_ASSERT(STATUS_SUCCESS == (status))
static inline
NTSTATUS
TimeNow(
PLONG64 pllNow
)
{
struct timeval tv;
if (gettimeofday(&tv, NULL))
{
return LwErrnoToNtStatus(errno);
}
else
{
*pllNow =
tv.tv_sec * 1000000000ll +
tv.tv_usec * 1000ll;
return STATUS_SUCCESS;
}
}
PLW_THREAD_POOL gpPool = NULL;
pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t gEvent = PTHREAD_COND_INITIALIZER;
MU_FIXTURE_SETUP(Task)
{
MU_ASSERT_STATUS_SUCCESS(
LwRtlCreateThreadPool(&gpPool));
}
MU_FIXTURE_TEARDOWN(Task)
{
LwRtlFreeThreadPool(&gpPool);
}
static
VOID
BasicWorkItem(
PVOID pContext
)
{
BOOLEAN volatile *pbValue = pContext;
pthread_mutex_lock(&gLock);
*pbValue = TRUE;
pthread_cond_signal(&gEvent);
pthread_mutex_unlock(&gLock);
}
MU_TEST(Task, BasicWorkItem)
{
BOOLEAN volatile bValue = FALSE;
MU_ASSERT_STATUS_SUCCESS(LwRtlQueueWorkItem(
gpPool,
BasicWorkItem,
(PVOID) &bValue,
0));
pthread_mutex_lock(&gLock);
while (!bValue)
{
pthread_cond_wait(&gEvent, &gLock);
}
pthread_mutex_unlock(&gLock);
}
static const int gTarget = 5;
static
VOID
Timer(
PLW_TASK pTask,
PVOID pContext,
LW_TASK_EVENT_MASK WakeMask,
LW_TASK_EVENT_MASK* pWaitMask,
PLONG64 pllTime
)
{
int volatile *pValue = pContext;
if (*pValue < gTarget)
{
(*pValue)++;
*pWaitMask = LW_TASK_EVENT_TIME;
*pllTime = 10000000ll; /* 10 ms */
}
else
{
*pWaitMask = 0;
}
}
MU_TEST(Task, Timer)
{
int value = 0;
PLW_TASK pTask = NULL;
MU_ASSERT_STATUS_SUCCESS(LwRtlCreateTask(
gpPool,
&pTask,
NULL,
Timer,
(PVOID) &value));
LwRtlWakeTask(pTask);
LwRtlWaitTask(pTask);
LwRtlReleaseTask(&pTask);
MU_ASSERT_EQUAL(MU_TYPE_INTEGER, value, gTarget);
}
static
VOID
Yield(
PLW_TASK pTask,
PVOID pContext,
LW_TASK_EVENT_MASK WakeMask,
PLW_TASK_EVENT_MASK pWaitMask,
PLONG64 pllTime
)
{
int volatile *pValue = pContext;
if (WakeMask & LW_TASK_EVENT_INIT)
{
MU_ASSERT(*pValue == 0);
}
if (*pValue < gTarget)
{
(*pValue)++;
*pWaitMask = LW_TASK_EVENT_YIELD;
}
else
{
*pWaitMask = 0;
}
}
MU_TEST(Task, Yield)
{
int value1 = 0;
int value2 = 0;
PLW_TASK pTask1 = NULL;
PLW_TASK pTask2 = NULL;
PLW_TASK_GROUP pGroup = NULL;
MU_ASSERT_STATUS_SUCCESS(LwRtlCreateTaskGroup(
gpPool,
&pGroup));
MU_ASSERT_STATUS_SUCCESS(LwRtlCreateTask(
gpPool,
&pTask1,
pGroup,
Yield,
(PVOID) &value1));
MU_ASSERT_STATUS_SUCCESS(LwRtlCreateTask(
gpPool,
&pTask1,
pGroup,
Yield,
(PVOID) &value2));
LwRtlWakeTaskGroup(pGroup);
LwRtlReleaseTask(&pTask1);
LwRtlReleaseTask(&pTask2);
LwRtlWaitTaskGroup(pGroup);
LwRtlFreeTaskGroup(&pGroup);
MU_ASSERT_EQUAL(MU_TYPE_INTEGER, value1, gTarget);
MU_ASSERT_EQUAL(MU_TYPE_INTEGER, value2, gTarget);
}
#define BUFFER_SIZE (64 * 1024)
#define SEND_SEGMENTS 1
#define NUM_ITERATIONS 16
#define NUM_PAIRS 500
MU_TEST(Task, Transceive)
{
static BENCHMARK_SETTINGS settings =
{
.ulBufferSize = BUFFER_SIZE,
.usSendSegments = SEND_SEGMENTS,
.ulIterations = NUM_ITERATIONS,
.ulPairs = NUM_PAIRS
};
ULONG64 ullTotal = 0;
ULONG64 ullTime = 0;
BenchmarkThreadPool(
gpPool,
&settings,
&ullTime,
&ullTotal);
MU_INFO("Transferred %llu bytes in %.2f seconds, %.2f mbit/s",
(unsigned long long) ullTotal,
ullTime / 1000000000.0,
(ullTotal / 131072.0) / (ullTime / 1000000000.0));
}