adding threading and read write lock tests

This commit is contained in:
ZappoMan 2014-03-17 17:07:42 -07:00
parent 9411519dc9
commit 14f8245dd8
10 changed files with 387 additions and 0 deletions

View file

@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 2.8)
if (WIN32)
cmake_policy (SET CMP0020 NEW)
endif (WIN32)
set(TARGET_NAME threads-tests)
set(ROOT_DIR ../..)
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
# setup for find modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/")
find_package(Qt5Core REQUIRED)
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME} TRUE)
include(${MACRO_DIR}/AutoMTC.cmake)
auto_mtc(${TARGET_NAME} ${ROOT_DIR})
qt5_use_modules(${TARGET_NAME} Core)
#include glm
include(${MACRO_DIR}/IncludeGLM.cmake)
include_glm(${TARGET_NAME} ${ROOT_DIR})
# link in the shared libraries
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
IF (WIN32)
#target_link_libraries(${TARGET_NAME} Winmm Ws2_32)
ENDIF(WIN32)

View file

@ -0,0 +1,65 @@
//
// SampleReadThread.cpp
// interface
//
// Created by Brad Hefta-Gaub on 2014.03.17
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree.
//
#include <QDebug>
#include <SharedUtil.h>
#include "SharedResource.h"
#include "SampleReadThread.h"
SampleReadThread::SampleReadThread(SharedResource* theResource, int id) :
_theResource(theResource),
_myID(id) {
}
bool SampleReadThread::process() {
const quint64 FRAME_RATE = 60;
const quint64 USECS_PER_FRAME = USECS_PER_SECOND / FRAME_RATE; // every 60fps
quint64 start = usecTimestampNow();
_theResource->lockForRead();
quint64 end = usecTimestampNow();
quint64 elapsed = end - start;
int theValue = _theResource->getValue();
bool wantDebugging = true;
if (wantDebugging) {
qDebug() << "SampleReadThread::process()... _myID=" << _myID << "lockForRead() took" << elapsed << "usecs" <<
" _theResource->getValue()=" << theValue;
}
quint64 startWork = usecTimestampNow();
{
const int LOTS_OF_OPERATIONS = 100000;
for(int i = 0; i < LOTS_OF_OPERATIONS; i++) {
float x = rand();
float y = rand();
float z = x * y;
}
}
quint64 endWork = usecTimestampNow();
quint64 elapsedWork = endWork - startWork;
qDebug() << "SampleReadThread::process()... _myID=" << _myID << " work took" << elapsedWork << "usecs";
_theResource->unlock();
if (isStillRunning()) {
if (elapsed < USECS_PER_FRAME) {
quint64 sleepFor = USECS_PER_FRAME - elapsed;
usleep(sleepFor);
} else {
usleep(5); // sleep at least a little
}
}
return isStillRunning(); // keep running till they terminate us
}

View file

@ -0,0 +1,31 @@
//
// SampleReadThread.h
// tests
//
// Created by Brad Hefta-Gaub on 2014.03.17
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__SampleReadThread__
#define __interface__SampleReadThread__
#include <GenericThread.h>
class SharedResource;
/// Generalized threaded processor for handling received inbound packets.
class SampleReadThread : public GenericThread {
Q_OBJECT
public:
SampleReadThread(SharedResource* theResource, int id);
protected:
/// Implements generic processing behavior for this thread.
virtual bool process();
private:
SharedResource* _theResource;
int _myID;
};
#endif // __interface__SampleReadThread__

View file

@ -0,0 +1,47 @@
//
// SampleWriteThread.cpp
// interface
//
// Created by Brad Hefta-Gaub on 2014.03.17
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree.
//
#include <QDebug>
#include <SharedUtil.h>
#include "SharedResource.h"
#include "SampleWriteThread.h"
SampleWriteThread::SampleWriteThread(SharedResource* theResource) :
_theResource(theResource) {
}
bool SampleWriteThread::process() {
const quint64 USECS_PER_OPERATION = USECS_PER_SECOND * 1; // once every second.
quint64 start = usecTimestampNow();
_theResource->lockForWrite();
quint64 end = usecTimestampNow();
quint64 elapsed = end - start;
int theValue = _theResource->incrementValue();
bool wantDebugging = false;
if (wantDebugging) {
qDebug() << "SampleWriteThread::process()... lockForWrite() took" << elapsed << "usecs" <<
" _theResource->incrementValue()=" << theValue;
}
_theResource->unlock();
if (isStillRunning()) {
if (elapsed < USECS_PER_OPERATION) {
quint64 sleepFor = USECS_PER_OPERATION - elapsed;
usleep(sleepFor);
}
}
return isStillRunning(); // keep running till they terminate us
}

View file

@ -0,0 +1,30 @@
//
// SampleWriteThread.h
// tests
//
// Created by Brad Hefta-Gaub on 2014.03.17
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__SampleWriteThread__
#define __interface__SampleWriteThread__
#include <GenericThread.h>
class SharedResource;
/// Generalized threaded processor for handling received inbound packets.
class SampleWriteThread : public GenericThread {
Q_OBJECT
public:
SampleWriteThread(SharedResource* theResource);
protected:
/// Implements generic processing behavior for this thread.
virtual bool process();
private:
SharedResource* _theResource;
};
#endif // __interface__SampleWriteThread__

View file

@ -0,0 +1,38 @@
//
// SharedResource.cpp
// tests
//
// Created by Brad Hefta-Gaub on 2014.03.17
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <SharedUtil.h>
#include "SharedResource.h"
const int MOVING_AVERAGE_SAMPLES = 10000;
SharedResource::SharedResource() :
_value(0),
_lockAverage(MOVING_AVERAGE_SAMPLES),
_lockForReadAverage(MOVING_AVERAGE_SAMPLES),
_lockForWriteAverage(MOVING_AVERAGE_SAMPLES)
{
};
void SharedResource::lockForRead() {
quint64 start = usecTimestampNow();
_lock.lockForRead();
quint64 end = usecTimestampNow();
quint64 elapsed = end - start;
_lockForReadAverage.updateAverage(elapsed);
_lockAverage.updateAverage(elapsed);
}
void SharedResource::lockForWrite() {
quint64 start = usecTimestampNow();
_lock.lockForWrite();
quint64 end = usecTimestampNow();
quint64 elapsed = end - start;
_lockForWriteAverage.updateAverage(elapsed);
_lockAverage.updateAverage(elapsed);
}

View file

@ -0,0 +1,40 @@
//
// SharedResource.h
// tests
//
// Created by Brad Hefta-Gaub on 2014.03.17
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__SharedResource__
#define __interface__SharedResource__
#include <QReadWriteLock>
#include <SimpleMovingAverage.h>
/// Generalized threaded processor for handling received inbound packets.
class SharedResource {
public:
SharedResource();
void lockForRead();
void lockForWrite();
void unlock() { _lock.unlock(); }
int getValue() const { return _value; }
int incrementValue() { return ++_value; }
float getAverageLockTime() const { return _lockAverage.getAverage(); }
float getAverageLockForReadTime() const { return _lockForReadAverage.getAverage(); }
float getAverageLockForWriteTime() const { return _lockForWriteAverage.getAverage(); }
private:
QReadWriteLock _lock;
int _value;
SimpleMovingAverage _lockAverage;
SimpleMovingAverage _lockForReadAverage;
SimpleMovingAverage _lockForWriteAverage;
};
#endif // __interface__SharedResource__

View file

@ -0,0 +1,73 @@
//
// ThreadsTests.cpp
// thread-tests
//
// Created by Brad Hefta-Gaub on 2014.03.17
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
#include <QDebug>
#include <QReadWriteLock>
#include <GenericThread.h>
#include <SharedUtil.h>
#include "SampleReadThread.h"
#include "SampleWriteThread.h"
#include "SharedResource.h"
#include "ThreadsTests.h"
void ThreadsTests::runAllTests() {
qDebug() << "START ThreadsTests::runAllTests()";
const quint64 TOTAL_RUN_TIME = USECS_PER_SECOND * 10; // run for 2 minutes
const quint64 MAIN_THREAD_SLEEP = USECS_PER_SECOND * 0.25; // main thread checks in every 1/4 second
quint64 start = usecTimestampNow();
quint64 now = usecTimestampNow();
SharedResource resource;
const int NUMBER_OF_READERS = 125; // + 3 = 128, Max number of QThreads on the mac.
QVector<SampleReadThread*> readThreads;
for(int i = 0; i < NUMBER_OF_READERS; i++) {
SampleReadThread* newReader = new SampleReadThread(&resource, i);
newReader->initialize();
readThreads.append(newReader);
}
SampleWriteThread write(&resource);
write.initialize();
while(now - start < TOTAL_RUN_TIME) {
float elapsed = (float)(now - start) / (float)USECS_PER_SECOND;
qDebug() << "Main thread still running... elapsed:" << elapsed << "seconds";
qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs";
qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs";
qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs";
qDebug() << " resource.value:" << resource.getValue();
usleep(MAIN_THREAD_SLEEP);
now = usecTimestampNow();
}
write.terminate();
foreach(SampleReadThread* readThread, readThreads) {
readThread->terminate();
delete readThread;
}
readThreads.clear();
qDebug() << "DONE running...";
qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs";
qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs";
qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs";
qDebug() << " resource.value:" << resource.getValue();
qDebug() << "END ThreadsTests::runAllTests()";
qDebug() << "_POSIX_THREAD_THREADS_MAX" << _POSIX_THREAD_THREADS_MAX;
qDebug() << "QThread::idealThreadCount()" << QThread::idealThreadCount();
}

View file

@ -0,0 +1,16 @@
//
// ThreadsTests.h
// threads-tests
//
// Created by Brad Hefta-Gaub on 2014.03.17
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
#ifndef __tests__ThreadsTests__
#define __tests__ThreadsTests__
namespace ThreadsTests {
void runAllTests();
}
#endif // __tests__ThreadsTests__

View file

@ -0,0 +1,11 @@
//
// main.cpp
// threads-tests
//
#include "ThreadsTests.h"
int main(int argc, char** argv) {
ThreadsTests::runAllTests();
return 0;
}