2002-10-10 01:04:15 +00:00
|
|
|
#include "uperf.h"
|
|
|
|
|
|
|
|
static const char delim = '/';
|
|
|
|
static int32_t execCount = 0;
|
|
|
|
UPerfTest* UPerfTest::gTest = NULL;
|
|
|
|
static const int MAXLINES = 40000;
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
HELP1,
|
|
|
|
HELP2,
|
|
|
|
VERBOSE,
|
|
|
|
SOURCEDIR,
|
|
|
|
ENCODING,
|
|
|
|
USELEN,
|
|
|
|
FILE_NAME,
|
|
|
|
PASSES,
|
|
|
|
ITERATIONS,
|
|
|
|
TIME,
|
|
|
|
LINE_MODE,
|
|
|
|
BULK_MODE
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
UOption options[]={
|
|
|
|
UOPTION_HELP_H,
|
|
|
|
UOPTION_HELP_QUESTION_MARK,
|
|
|
|
UOPTION_VERBOSE,
|
|
|
|
UOPTION_SOURCEDIR,
|
|
|
|
UOPTION_ENCODING,
|
|
|
|
UOPTION_DEF( "uselen", 'u', UOPT_NO_ARG),
|
|
|
|
UOPTION_DEF( "file-name", 'f', UOPT_REQUIRES_ARG),
|
|
|
|
UOPTION_DEF( "passes", 'p', UOPT_REQUIRES_ARG),
|
|
|
|
UOPTION_DEF( "iterations", 'i', UOPT_REQUIRES_ARG),
|
|
|
|
UOPTION_DEF( "time", 't', UOPT_REQUIRES_ARG),
|
|
|
|
UOPTION_DEF( "line-mode", 'l', UOPT_NO_ARG),
|
|
|
|
UOPTION_DEF( "bulk-mode", 'b', UOPT_NO_ARG),
|
|
|
|
};
|
|
|
|
|
|
|
|
UPerfTest::UPerfTest(int32_t argc, const char* argv[], UErrorCode& status){
|
|
|
|
|
|
|
|
_argc = argc;
|
|
|
|
_argv = argv;
|
|
|
|
ucharBuf = NULL;
|
|
|
|
encoding = "";
|
|
|
|
uselen = FALSE;
|
|
|
|
fileName = NULL;
|
|
|
|
sourceDir = NULL;
|
|
|
|
lines = NULL;
|
|
|
|
numLines = 0;
|
|
|
|
line_mode = FALSE;
|
|
|
|
buffer = NULL;
|
|
|
|
bufferLen = 0;
|
|
|
|
verbose = FALSE;
|
|
|
|
bulk_mode = FALSE;
|
|
|
|
passes = iterations = time = 0;
|
|
|
|
|
|
|
|
//initialize the argument list
|
|
|
|
U_MAIN_INIT_ARGS(argc, argv);
|
|
|
|
//parse the arguments
|
|
|
|
_remainingArgc = u_parseArgs(argc, (char**)argv, (int32_t)(sizeof(options)/sizeof(options[0])), options);
|
|
|
|
|
|
|
|
// Now setup the arguments
|
|
|
|
if(argc==1 || options[HELP1].doesOccur || options[HELP2].doesOccur) {
|
|
|
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(options[VERBOSE].doesOccur) {
|
|
|
|
verbose = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(options[SOURCEDIR].doesOccur) {
|
|
|
|
sourceDir = options[SOURCEDIR].value;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(options[ENCODING].doesOccur) {
|
|
|
|
encoding = options[ENCODING].value;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(options[USELEN].doesOccur) {
|
|
|
|
uselen = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(options[FILE_NAME].doesOccur){
|
|
|
|
fileName = options[FILE_NAME].value;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(options[PASSES].doesOccur) {
|
|
|
|
passes = atoi(options[PASSES].value);
|
|
|
|
}
|
|
|
|
if(options[ITERATIONS].doesOccur) {
|
|
|
|
iterations = atoi(options[ITERATIONS].value);
|
|
|
|
time =0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(options[TIME].doesOccur) {
|
|
|
|
time = atoi(options[TIME].value);
|
|
|
|
iterations = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(options[LINE_MODE].doesOccur) {
|
|
|
|
line_mode = TRUE;
|
|
|
|
bulk_mode = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(options[BULK_MODE].doesOccur) {
|
|
|
|
bulk_mode = TRUE;
|
|
|
|
line_mode = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(time > 0 && iterations >0){
|
|
|
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t len = 0;
|
|
|
|
resolvedFileName = NULL;
|
|
|
|
if(fileName!=NULL){
|
|
|
|
//pre-flight
|
|
|
|
ucbuf_resolveFileName(sourceDir, fileName,resolvedFileName,&len, &status);
|
|
|
|
resolvedFileName = (char*) uprv_malloc(len);
|
|
|
|
if(fileName==NULL){
|
|
|
|
status= U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(status == U_BUFFER_OVERFLOW_ERROR){
|
|
|
|
status = U_ZERO_ERROR;
|
|
|
|
}
|
|
|
|
ucbuf_resolveFileName(sourceDir, fileName, resolvedFileName, &len, &status);
|
|
|
|
ucharBuf = ucbuf_open(resolvedFileName,&encoding,TRUE,FALSE,&status);
|
|
|
|
|
|
|
|
if(U_FAILURE(status)){
|
|
|
|
printf("Could not open the input file %s. Error: %s\n", fileName, u_errorName(status));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ULine* UPerfTest::getLines(UErrorCode& status){
|
|
|
|
lines = new ULine[MAXLINES];
|
|
|
|
numLines=0;
|
|
|
|
const UChar* line=NULL;
|
|
|
|
int32_t len =0;
|
|
|
|
for (;;) {
|
|
|
|
line = ucbuf_readline(ucharBuf,&len,&status);
|
|
|
|
if(status == U_EOF||U_FAILURE(status)){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lines[numLines].name = new UChar[len];
|
|
|
|
lines[numLines].len = len;
|
|
|
|
memcpy(lines[numLines].name, line, len * U_SIZEOF_UCHAR);
|
|
|
|
|
|
|
|
numLines++;
|
|
|
|
len = 0;
|
|
|
|
if (numLines >= MAXLINES) {
|
|
|
|
fprintf(stderr, "File too big. Max number of lines is %d\n", MAXLINES);
|
|
|
|
status= U_ILLEGAL_ARGUMENT_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(status==U_EOF){
|
|
|
|
status =U_ZERO_ERROR;
|
|
|
|
}
|
|
|
|
return lines;
|
|
|
|
}
|
|
|
|
const UChar* UPerfTest::getBuffer(int32_t& len, UErrorCode& status){
|
|
|
|
buffer = ucbuf_getBuffer(ucharBuf,&bufferLen,&status);
|
|
|
|
len = bufferLen;
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
UBool UPerfTest::run(){
|
|
|
|
if(_remainingArgc==1){
|
|
|
|
// Testing all methods
|
|
|
|
return runTest();
|
|
|
|
}
|
|
|
|
// Test only the specified fucntion
|
|
|
|
for (int i = 1; i < _remainingArgc; ++i) {
|
|
|
|
if (_argv[i][0] != '-') {
|
|
|
|
char* name = (char*) _argv[i];
|
|
|
|
if(verbose==TRUE){
|
|
|
|
fprintf(stdout, "\n=== Handling test: %s: ===\n", name);
|
|
|
|
}
|
|
|
|
char* parameter = strchr( name, '@' );
|
|
|
|
if (parameter) {
|
|
|
|
*parameter = 0;
|
|
|
|
parameter += 1;
|
|
|
|
}
|
|
|
|
execCount = 0;
|
|
|
|
UBool res = runTest( name, parameter );
|
|
|
|
if (!res || (execCount <= 0)) {
|
|
|
|
fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
UBool UPerfTest::runTest(char* name, char* par ){
|
|
|
|
UBool rval;
|
|
|
|
char* pos = NULL;
|
|
|
|
|
|
|
|
if (name)
|
|
|
|
pos = strchr( name, delim ); // check if name contains path (by looking for '/')
|
|
|
|
if (pos) {
|
|
|
|
path = pos+1; // store subpath for calling subtest
|
|
|
|
*pos = 0; // split into two strings
|
|
|
|
}else{
|
|
|
|
path = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) {
|
|
|
|
rval = runTestLoop( NULL, NULL );
|
|
|
|
|
|
|
|
}else if (strcmp( name, "LIST" ) == 0) {
|
|
|
|
this->usage();
|
|
|
|
rval = TRUE;
|
|
|
|
|
|
|
|
}else{
|
|
|
|
rval = runTestLoop( name, par );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pos)
|
|
|
|
*pos = delim; // restore original value at pos
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UPerfTest::setPath( char* pathVal )
|
|
|
|
{
|
|
|
|
this->path = pathVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
// call individual tests, to be overriden to call implementations
|
|
|
|
UPerfFunction* UPerfTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
|
|
|
|
{
|
|
|
|
// to be overriden by a method like:
|
|
|
|
/*
|
|
|
|
switch (index) {
|
|
|
|
case 0: name = "First Test"; if (exec) FirstTest( par ); break;
|
|
|
|
case 1: name = "Second Test"; if (exec) SecondTest( par ); break;
|
|
|
|
default: name = ""; break;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
fprintf(stderr,"*** runIndexedTest needs to be overriden! ***");
|
|
|
|
name = ""; exec = exec; index = index; par = par;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UBool UPerfTest::runTestLoop( char* testname, char* par )
|
|
|
|
{
|
|
|
|
int32_t index = 0;
|
|
|
|
const char* name;
|
|
|
|
UBool run_this_test;
|
|
|
|
UBool rval = FALSE;
|
|
|
|
|
|
|
|
UPerfTest* saveTest = gTest;
|
|
|
|
gTest = this;
|
|
|
|
do {
|
|
|
|
this->runIndexedTest( index, FALSE, name );
|
|
|
|
if (!name || (name[0] == 0))
|
|
|
|
break;
|
|
|
|
if (!testname) {
|
|
|
|
run_this_test = TRUE;
|
|
|
|
}else{
|
|
|
|
run_this_test = (UBool) (strcmp( name, testname ) == 0);
|
|
|
|
}
|
|
|
|
if (run_this_test) {
|
|
|
|
UPerfFunction* testFunction = this->runIndexedTest( index, TRUE, name, par );
|
|
|
|
execCount++;
|
|
|
|
rval=TRUE;
|
|
|
|
if(testFunction==NULL){
|
|
|
|
fprintf(stderr,"%s function returned NULL", name);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (testFunction->getOperationsPerIteration() < 1) {
|
|
|
|
fprintf(stderr, "%s returned an illegal operations/iteration()", name);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2002-10-11 23:12:31 +00:00
|
|
|
double t=0;
|
2002-10-10 01:04:15 +00:00
|
|
|
int32_t n = 1;
|
|
|
|
long events = -1;
|
|
|
|
if (iterations > 0) {
|
|
|
|
n = iterations;
|
|
|
|
// print info only if in verbose mode
|
|
|
|
if(verbose==TRUE){
|
|
|
|
fprintf(stdout,"= %s begin %i \n" ,name, n);
|
|
|
|
}
|
|
|
|
// Run the test function for specified of passe and iterations
|
|
|
|
for(int32_t ps =0; ps < passes; ps++){
|
|
|
|
t = testFunction->time(n);
|
|
|
|
}
|
|
|
|
events = testFunction->getEventsPerIteration();
|
|
|
|
} else {
|
|
|
|
n = time;
|
|
|
|
// Run for specified duration in seconds
|
|
|
|
if(verbose==TRUE){
|
|
|
|
fprintf(stdout,"= %s begin %i seconds \n" ,name, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
//n *= 1000; // s => ms
|
|
|
|
//System.out.println("# " + meth.getName() + " " + n + " sec");
|
|
|
|
for(int32_t ps=0;ps<passes;ps++){
|
|
|
|
int32_t loops = 0;
|
|
|
|
int32_t failsafe = 1; // last resort for very fast methods
|
|
|
|
t = 0;
|
|
|
|
while (t < (int)(n * 0.9)) { // 90% is close enough
|
|
|
|
if (loops == 0 || t == 0) {
|
|
|
|
loops = failsafe;
|
|
|
|
failsafe *= 10;
|
|
|
|
} else {
|
|
|
|
//System.out.println("# " + meth.getName() + " x " + loops + " = " + t);
|
|
|
|
loops = (int)((double)n / t * loops + 0.5);
|
|
|
|
if (loops == 0) {
|
|
|
|
fprintf(stderr,"Unable to converge on desired duration");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//System.out.println("# " + meth.getName() + " x " + loops);
|
|
|
|
t = testFunction->time(loops);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
events = testFunction->getEventsPerIteration();
|
|
|
|
}
|
|
|
|
//print info only in verbose mode
|
|
|
|
if(verbose==TRUE){
|
2002-10-11 23:12:31 +00:00
|
|
|
if(events == -1){
|
2002-10-10 01:04:15 +00:00
|
|
|
fprintf(stdout,"= %s end: %f operations: %i \n",name , t , testFunction->getOperationsPerIteration());
|
|
|
|
}else{
|
|
|
|
fprintf(stdout,"= %s end: %f operations: %i events: %i\n",name , t , testFunction->getOperationsPerIteration(), events);
|
|
|
|
}
|
|
|
|
}else{
|
2002-10-11 23:12:31 +00:00
|
|
|
if(events == -1){
|
2002-10-10 01:04:15 +00:00
|
|
|
fprintf(stdout,"= %f %i \n", t , testFunction->getOperationsPerIteration());
|
|
|
|
}else{
|
|
|
|
fprintf(stdout,"= %f %i %i\n", t , testFunction->getOperationsPerIteration(), events);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete testFunction;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}while(name);
|
|
|
|
|
|
|
|
gTest = saveTest;
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Print a usage message for this test class.
|
|
|
|
*/
|
|
|
|
void UPerfTest::usage( void )
|
|
|
|
{
|
|
|
|
UBool save_verbose = verbose;
|
|
|
|
verbose = TRUE;
|
|
|
|
fprintf(stdout,"Test names:\n");
|
|
|
|
fprintf(stdout,"-----------\n");
|
|
|
|
|
|
|
|
int32_t index = 0;
|
|
|
|
const char* name = NULL;
|
|
|
|
do{
|
|
|
|
this->runIndexedTest( index, FALSE, name );
|
|
|
|
if (!name) break;
|
|
|
|
fprintf(stdout,name);
|
|
|
|
fprintf(stdout,"\n");
|
|
|
|
index++;
|
|
|
|
}while (name && (name[0] != 0));
|
|
|
|
verbose = save_verbose;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UPerfTest::setCaller( UPerfTest* callingTest )
|
|
|
|
{
|
|
|
|
caller = callingTest;
|
|
|
|
if (caller) {
|
|
|
|
verbose = caller->verbose;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UBool UPerfTest::callTest( UPerfTest& testToBeCalled, char* par )
|
|
|
|
{
|
|
|
|
execCount--; // correct a previously assumed test-exec, as this only calls a subtest
|
|
|
|
testToBeCalled.setCaller( this );
|
|
|
|
return testToBeCalled.runTest( path, par );
|
|
|
|
}
|
|
|
|
|
|
|
|
UPerfTest::~UPerfTest(){
|
|
|
|
if(lines!=NULL){
|
|
|
|
delete[] lines;
|
|
|
|
}
|
|
|
|
ucbuf_close(ucharBuf);
|
2002-10-10 16:23:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|