2024-03-02 17:58:28 +02:00
# ifdef _WIN32
# include <Windows.h>
# include <conio.h>
# endif
# include <iostream>
# include <iomanip>
# include <stdint.h>
# include <ctime>
# include <time.h>
# include <omp.h>
# include <queue>
2024-03-02 20:44:27 +02:00
# include <deque>
2024-03-02 17:58:28 +02:00
# include <vector>
# include <string>
# include <memory>
# include <cmath>
# include "BiasAndAC.h"
# include "Monkey.h"
# include "Serial.h"
# include "Entropy.h"
# include "Stat.h"
# include "Gamma.h"
# include "KolmogorovSmirnov.h"
int deviceType_ ;
int rxBytes ;
int blockIntCount ;
bool doExit = false ;
using namespace std ;
# ifdef __linux
# include <signal.h>
// Terminal Signal Handler
void sigintevent ( int )
{
doExit = true ;
}
# endif
2024-03-02 20:44:27 +02:00
# define _BSD_SOURCE
# include <sys/time.h>
2024-03-02 17:58:28 +02:00
int main ( )
{
// try this to resize terminal
// resizeterm(42, 80);
# ifdef _WIN32
// hide cursor
CONSOLE_CURSOR_INFO info ;
info . dwSize = 100 ;
info . bVisible = FALSE ;
SetConsoleCursorInfo ( GetStdHandle ( STD_OUTPUT_HANDLE ) , & info ) ;
// clear screen
system ( " cls " ) ;
# elif __linux
// clear screen
2024-03-02 18:18:25 +02:00
// cout << "\E[?25l\E[H\E[2J";
2024-03-02 17:58:28 +02:00
// Signal handler to catch CTRL-C in terminal
signal ( SIGINT , ( __sighandler_t ) & sigintevent ) ;
# elif MACOSX
# endif
// randtest classes
CBiasAndAC biasAndAc ;
biasAndAc . ResetAll ( ) ;
CMonkey oqso ;
CSerial serial ;
CEntropy entropy ;
CGamma gamma ;
CKolmogorovSmirnov ks ;
double serialP = 0.5 ;
double serialZ = 0.0 ;
double KSP ;
double KSN ;
time_t startTime ;
time ( & startTime ) ;
string sTime = ctime ( & startTime ) ;
char sStartTime [ 16 ] ;
sTime . copy ( sStartTime , 15 , 4 ) ;
time_t timeNow ;
time_t timePrev ;
time ( & timePrev ) ;
timePrev - = 8 ;
2024-03-02 20:44:27 +02:00
queue < shared_ptr < vector < uint32_t > > > dataQueue ;
2024-03-02 17:58:28 +02:00
double bitsThroughputCount = 0 ;
double prevBitsThroughputCount = 0 ;
double bitsTestedCount = 0 ;
double bitsTestedRatio = 1 ;
double prevBitsTestedCount = 0 ;
# ifdef _WIN32
LARGE_INTEGER countFreq ;
QueryPerformanceFrequency ( & countFreq ) ;
LARGE_INTEGER prevCount ;
QueryPerformanceCounter ( & prevCount ) ;
LARGE_INTEGER nowCount ;
# elif __linux
timeval start , stop ;
double newTimeInterval ;
gettimeofday ( & start , NULL ) ;
# elif MACOSX
# endif
double throughput = 0 ;
vector < double > metaPs ;
vector < double > meterZs ;
vector < int > meterFlags ( 36 , 0 ) ;
double meterScore = 0 ;
bool meterFreeze = false ;
2024-03-02 20:44:27 +02:00
omp_set_nested ( true ) ;
2024-03-02 17:58:28 +02:00
2024-03-02 20:44:27 +02:00
# pragma omp parallel sections num_threads(2)
2024-03-02 19:01:51 +02:00
{
2024-03-02 20:44:27 +02:00
2024-03-02 17:58:28 +02:00
# pragma omp section
{
2024-03-02 20:44:27 +02:00
// This section reads from stdin as binary data and enqueues it for testing
const size_t blockSize = 2048 ; // Number of uint32_t values in a block
const size_t bytesPerValue = sizeof ( uint32_t ) ;
const size_t bufferSize = blockSize * bytesPerValue ; // Total bytes per block
char buffer [ bufferSize ] ; // Temporary buffer to store bytes
while ( ! cin . eof ( ) & & ! doExit ) {
cin . read ( buffer , bufferSize ) ;
size_t bytesRead = cin . gcount ( ) ;
// Convert read bytes to uint32_t and store in a vector
shared_ptr < vector < uint32_t > > newBuffer ( new vector < uint32_t > ( ) ) ;
for ( size_t i = 0 ; i < bytesRead ; i + = bytesPerValue ) {
if ( i + bytesPerValue < = bytesRead ) {
// Ensure we have a full 4 bytes to read
uint32_t value = 0 ;
memcpy ( & value , buffer + i , bytesPerValue ) ;
newBuffer - > push_back ( value ) ;
2024-03-02 18:18:25 +02:00
}
}
2024-03-02 20:44:27 +02:00
if ( ! newBuffer - > empty ( ) ) {
# pragma omp critical
dataQueue . push ( newBuffer ) ;
2024-03-02 17:58:28 +02:00
}
}
2024-03-02 20:44:27 +02:00
doExit = true ; // Exit if stdin closes or reaches EOF
2024-03-02 19:01:51 +02:00
}
2024-03-02 17:58:28 +02:00
2024-03-02 20:44:27 +02:00
2024-03-02 17:58:28 +02:00
# pragma omp section
{
2024-03-02 20:44:27 +02:00
// This section processes the enqueued data
while ( ! doExit | | ! dataQueue . empty ( ) ) {
shared_ptr < vector < uint32_t > > testBuffer = nullptr ;
# pragma omp critical
2024-03-02 17:58:28 +02:00
{
2024-03-02 20:44:27 +02:00
if ( ! dataQueue . empty ( ) ) {
testBuffer = dataQueue . front ( ) ;
dataQueue . pop ( ) ;
2024-03-02 17:58:28 +02:00
}
2024-03-02 20:44:27 +02:00
}
2024-03-02 17:58:28 +02:00
2024-03-02 20:44:27 +02:00
if ( testBuffer ! = nullptr ) {
// Parallel processing of the testBuffer
# pragma omp parallel sections num_threads(4)
2024-03-02 17:58:28 +02:00
{
2024-03-02 20:44:27 +02:00
# pragma omp section
{ for ( uint32_t value : * testBuffer ) biasAndAc . InsertWord32 ( value ) ; }
# pragma omp section
{ for ( uint32_t value : * testBuffer ) oqso . InsertWord32 ( value ) ; }
# pragma omp section
{ for ( uint32_t value : * testBuffer ) serial . InsertWord32 ( value ) ; }
# pragma omp section
{ for ( uint32_t value : * testBuffer ) entropy . InsertWord32 ( value ) ; }
2024-03-02 17:58:28 +02:00
}
2024-03-02 20:44:27 +02:00
2024-03-02 17:58:28 +02:00
// Display results
2024-03-02 20:44:27 +02:00
time ( & timeNow ) ;
if ( difftime ( timeNow , timePrev ) > = 10 )
2024-03-02 17:58:28 +02:00
{
// calc rates
2024-03-02 20:44:27 +02:00
# ifdef _WIN32
QueryPerformanceCounter ( & nowCount ) ;
double newTimeInterval = ( ( double ) nowCount . QuadPart - prevCount . QuadPart ) / countFreq . QuadPart ;
prevCount = nowCount ;
# elif __linux
gettimeofday ( & stop , NULL ) ;
newTimeInterval = ( stop . tv_sec - start . tv_sec ) ; // sec
newTimeInterval + = ( stop . tv_usec - start . tv_usec ) / 1000000.0 ; // us to sec
start = stop ;
# elif MACOSX
# endif
2024-03-02 17:58:28 +02:00
double newBitInterval ;
double newRate ;
2024-03-02 20:44:27 +02:00
# pragma omp critical
2024-03-02 17:58:28 +02:00
{
2024-03-02 20:44:27 +02:00
newBitInterval = ( bitsThroughputCount - prevBitsThroughputCount ) ;
prevBitsThroughputCount = bitsThroughputCount ;
2024-03-02 17:58:28 +02:00
}
newRate = newBitInterval / newTimeInterval ;
if ( throughput = = 0 )
2024-03-02 20:44:27 +02:00
throughput = newRate ;
2024-03-02 17:58:28 +02:00
else
2024-03-02 20:44:27 +02:00
throughput = ( 2 * throughput + newRate ) / 3 ;
2024-03-02 17:58:28 +02:00
2024-03-02 20:44:27 +02:00
double newBitsTestedRatio = ( bitsTestedCount - prevBitsTestedCount ) / newBitInterval ;
2024-03-02 17:58:28 +02:00
prevBitsTestedCount = bitsTestedCount ;
2024-03-02 20:44:27 +02:00
bitsTestedRatio = ( 2 * bitsTestedRatio + newBitsTestedRatio ) / 3 ;
2024-03-02 17:58:28 +02:00
if ( bitsTestedRatio > 1 )
2024-03-02 20:44:27 +02:00
bitsTestedRatio = 1 ;
2024-03-02 17:58:28 +02:00
// meta test and meter
2024-03-02 20:44:27 +02:00
metaPs . clear ( ) ;
meterZs . clear ( ) ;
2024-03-02 17:58:28 +02:00
if ( bitsTestedCount > = 65536 )
{
// Autocorrelation KS test
2024-03-02 20:44:27 +02:00
for ( int i = 0 ; i < 32 ; i + + )
2024-03-02 17:58:28 +02:00
{
2024-03-02 20:44:27 +02:00
metaPs . push_back ( biasAndAc . AC . P_Chi2 [ i ] ) ;
meterZs . push_back ( biasAndAc . AC . cumulativeACZScore [ i ] ) ;
2024-03-02 17:58:28 +02:00
}
double AcKSP ;
double AcKSN ;
2024-03-02 20:44:27 +02:00
ks . KSUP ( & AcKSP , & AcKSN , & metaPs [ 0 ] , metaPs . size ( ) ) ;
2024-03-02 17:58:28 +02:00
// Combined KS test
2024-03-02 20:44:27 +02:00
metaPs . push_back ( AcKSP ) ;
2024-03-02 17:58:28 +02:00
2024-03-02 20:44:27 +02:00
metaPs . push_back ( biasAndAc . Bias . P_Chi2 ) ;
meterZs . push_back ( biasAndAc . Bias . cumulativeBiasZScore ) ;
2024-03-02 17:58:28 +02:00
}
if ( bitsTestedCount > = 4194304 )
{
2024-03-02 20:44:27 +02:00
metaPs . push_back ( serial . P_Chi2 ) ;
serialP = gamma . Gamma ( 128. , serial . cumulativeSerialChi2 ) ;
serialZ = ks . PtoZ ( serialP ) ;
meterZs . push_back ( serialZ ) ;
2024-03-02 17:58:28 +02:00
2024-03-02 20:44:27 +02:00
metaPs . push_back ( entropy . P_Chi2 ) ;
meterZs . push_back ( entropy . cumulativeZScore ) ;
2024-03-02 17:58:28 +02:00
}
if ( bitsTestedCount > = 10485775 )
{
2024-03-02 20:44:27 +02:00
metaPs . push_back ( oqso . P_Chi2 ) ;
meterZs . push_back ( oqso . cumulativeZScore ) ;
2024-03-02 17:58:28 +02:00
}
if ( bitsTestedCount > = 65536 )
{
// This KS is combined AC KSP plus with other tests
2024-03-02 20:44:27 +02:00
ks . KSUP ( & KSP , & KSN , & metaPs [ 32 ] , metaPs . size ( ) - 32 ) ;
2024-03-02 17:58:28 +02:00
meterFreeze = false ;
2024-03-02 20:44:27 +02:00
for ( int i = 0 ; i < meterZs . size ( ) ; i + + )
2024-03-02 17:58:28 +02:00
{
// freeze condition
2024-03-02 20:44:27 +02:00
if ( fabs ( meterZs [ i ] ) > 4.264897 | | ( metaPs [ i ] < 0.00001 | | metaPs [ i ] > 0.99999 ) )
meterFlags [ i ] = - 1 ;
2024-03-02 17:58:28 +02:00
// unfreeze condition
if ( meterFlags [ i ] = = - 1 )
{
2024-03-02 20:44:27 +02:00
if ( fabs ( meterZs [ i ] ) < 2.326348 & & ( metaPs [ i ] > 0.01 & & metaPs [ i ] < 0.99 ) )
meterFlags [ i ] = 0 ;
2024-03-02 17:58:28 +02:00
}
if ( meterFlags [ i ] = = - 1 )
2024-03-02 20:44:27 +02:00
meterFreeze = true ;
2024-03-02 17:58:28 +02:00
}
// meter calc
if ( meterFreeze = = false )
2024-03-02 20:44:27 +02:00
meterScore = log ( bitsTestedCount ) / log ( 2. ) ;
2024-03-02 17:58:28 +02:00
}
cout < < endl ;
2024-03-02 20:44:27 +02:00
cout < < " QNGmeter Console 1.0 Test Type z-score p[z<=x] p[chi2<=x] " < < endl ;
cout < < " +---------------------------+------------------------------------------------+ " < < endl ;
cout < < " | | 1/0 Balance " < < setiosflags ( ios : : fixed ) < < setprecision ( 3 ) < < showpos < < biasAndAc . Bias . cumulativeBiasZScore < < " " < < setprecision ( 4 ) < < noshowpos < < CStat : : ZtoP ( biasAndAc . Bias . cumulativeBiasZScore ) < < " " < < biasAndAc . Bias . P_Chi2 < < " | " < < endl ;
cout < < " | | Serial Test " < < setiosflags ( ios : : fixed ) < < setprecision ( 3 ) < < showpos < < serialZ < < " " < < setprecision ( 4 ) < < noshowpos < < serialP < < " " < < serial . P_Chi2 < < " | " < < endl ;
cout < < " | | OQSO Test " < < setiosflags ( ios : : fixed ) < < setprecision ( 3 ) < < showpos < < oqso . cumulativeZScore < < " " < < setprecision ( 4 ) < < noshowpos < < CStat : : ZtoP ( oqso . cumulativeZScore ) < < " " < < oqso . P_Chi2 < < " | " < < endl ;
cout < < " | | Entropy Test " < < setiosflags ( ios : : fixed ) < < setprecision ( 3 ) < < showpos < < entropy . cumulativeZScore < < " " < < setprecision ( 4 ) < < noshowpos < < CStat : : ZtoP ( entropy . cumulativeZScore ) < < " " < < serial . P_Chi2 < < " | " < < endl ;
cout < < " | | H: " < < setiosflags ( ios : : fixed ) < < setprecision ( 9 ) < < entropy . E < < " | " < < endl ;
cout < < " | | | " < < endl ;
for ( int i = 1 ; i < = 32 ; i + + )
2024-03-02 17:58:28 +02:00
{
2024-03-02 20:44:27 +02:00
switch ( i )
{
case 2 :
cout < < " | Start Time | " ;
break ;
case 3 :
cout < < " | " < < sStartTime < < " | " ;
break ;
case 5 :
cout < < " | Total Bits Tested | " ;
break ;
case 6 :
cout < < " | " < < scientific < < setw ( 9 ) < < setprecision ( 2 ) < < bitsTestedCount < < fixed < < " | " ;
break ;
case 8 :
cout < < " | Throughput | " ;
break ;
case 9 :
cout < < " | " < < setiosflags ( ios : : fixed ) < < setw ( 4 ) < < setprecision ( 1 ) < < ( double ) ( throughput / 1000000.0 ) < < " Mbps | " ;
break ;
case 11 :
cout < < " | Bits Tested Percent | " ;
break ;
case 12 :
cout < < " | " < < setiosflags ( ios : : fixed ) < < setw ( 5 ) < < setprecision ( 1 ) < < ( 100 * bitsTestedRatio ) < < " % | " ;
break ;
case 18 :
cout < < " | Meta KS+ Test | " ;
break ;
case 19 :
cout < < " | " < < setiosflags ( ios : : fixed ) < < setw ( 5 ) < < setprecision ( 3 ) < < KSP < < " | " ;
break ;
case 22 :
cout < < " | Meta KS- Test | " ;
break ;
case 23 :
cout < < " | " < < setiosflags ( ios : : fixed ) < < setw ( 5 ) < < setprecision ( 3 ) < < KSN < < " | " ;
break ;
case 29 :
cout < < " | QNGmeter Score | " ;
break ;
case 30 :
cout < < " | " < < setiosflags ( ios : : fixed ) < < setw ( 4 ) < < setprecision ( 1 ) < < abs ( meterScore ) < < ( ( meterScore < 0 ) ? " - " : ( meterFreeze = = false ) ? " + " : " " ) < < " | " ;
break ;
default :
cout < < " | | " ;
}
cout < < " " < < setw ( 2 ) < < i < < " st AutoCorr " < < setiosflags ( ios : : fixed ) < < setprecision ( 3 ) < < showpos < < biasAndAc . AC . cumulativeACZScore [ i - 1 ] < < " " < < setprecision ( 4 ) < < noshowpos < < CStat : : ZtoP ( biasAndAc . AC . cumulativeACZScore [ i - 1 ] ) < < " " < < biasAndAc . AC . P_Chi2 [ i - 1 ] < < " | " < < endl ;
2024-03-02 17:58:28 +02:00
}
2024-03-02 20:44:27 +02:00
cout < < " +---------------------------+------------------------------------------------+ " < < endl ;
# ifdef _WIN32
// put cursor in top corner
COORD coord ;
coord . X = 0 ;
coord . Y = 0 ;
SetConsoleCursorPosition ( GetStdHandle ( STD_OUTPUT_HANDLE ) , coord ) ;
# elif __linux
// clear screen
// printf("\E[H");
# elif MACOSX
# endif
2024-03-02 17:58:28 +02:00
timePrev = timeNow ;
2024-03-02 20:44:27 +02:00
cout . flush ( ) ;
2024-03-02 17:58:28 +02:00
}
2024-03-02 20:44:27 +02:00
2024-03-02 17:58:28 +02:00
// End on an 'x' keypress
2024-03-02 20:44:27 +02:00
# ifdef _WIN32
if ( kbhit ( ) )
2024-03-02 17:58:28 +02:00
{
2024-03-02 20:44:27 +02:00
char c = getch_ ( ) ;
if ( tolower ( c ) = = ' x ' )
{
doExit = true ;
break ;
}
2024-03-02 17:58:28 +02:00
}
2024-03-02 20:44:27 +02:00
# elif __linux
// CRTL-C
# elif MACOSX
# endif
2024-03-02 17:58:28 +02:00
}
else
{
// give this thread a break from tight loop - waiting for data
2024-03-02 20:44:27 +02:00
usleep ( 1000 ) ;
2024-03-02 17:58:28 +02:00
}
}
}
}
}