2 **********************************************************************
3 * Copyright (C) 2010-2011, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
6 * file name: dicttrieperf.cpp
8 * tab size: 8 (not used)
11 * created on: 2010dec09
12 * created by: Markus W. Scherer
14 * Performance test program for dictionary-type tries.
16 * Usage from within <ICU build tree>/test/perf/dicttrieperf/ :
19 * export LD_LIBRARY_PATH=../../../lib:../../../stubdata:../../../tools/ctestfw
20 * ./dicttrieperf --sourcedir <ICU build tree>/data/out/tmp --passes 3 --iterations 1000
22 * ./dicttrieperf -f <ICU source tree>/source/data/brkitr/thaidict.txt --passes 3 --iterations 250
27 #include "unicode/bytestrie.h"
28 #include "unicode/bytestriebuilder.h"
29 #include "unicode/localpointer.h"
30 #include "unicode/ucharstrie.h"
31 #include "unicode/ucharstriebuilder.h"
32 #include "unicode/uperf.h"
33 #include "unicode/utext.h"
38 #include "ucbuf.h" // struct ULine
42 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
45 class DictionaryTriePerfTest
: public UPerfTest
{
47 DictionaryTriePerfTest(int32_t argc
, const char *argv
[], UErrorCode
&status
)
48 : UPerfTest(argc
, argv
, NULL
, 0, "", status
), numTextLines(0) {
51 for(int32_t i
=0; i
<numLines
; ++i
) {
52 // Skip comment lines (start with a character below 'A').
53 if(lines
[i
].name
[0]>=0x41) {
55 // Remove trailing CR LF.
56 int32_t len
=lines
[i
].len
;
58 while(len
>0 && ((c
=lines
[i
].name
[len
-1])==0xa || c
==0xd)) {
67 virtual UPerfFunction
*runIndexedTest(int32_t index
, UBool exec
, const char *&name
, char *par
=NULL
);
69 const char *getSourceDir() const { return sourceDir
; }
71 UBool
hasFile() const { return ucharBuf
!=NULL
; }
72 const ULine
*getCachedLines() const { return lines
; }
73 int32_t getNumLines() const { return numLines
; }
74 int32_t numTextLines
; // excluding comment lines
77 // Performance test function object.
78 // Loads icudt46l.dat (or whatever its current versioned filename)
79 // from the -s or --sourcedir path.
80 class PackageLookup
: public UPerfFunction
{
82 PackageLookup(const DictionaryTriePerfTest
&perf
) {
83 IcuToolErrorCode
errorCode("PackageLookup()");
84 CharString
filename(perf
.getSourceDir(), errorCode
);
85 int32_t filenameLength
=filename
.length();
86 if(filenameLength
>0 && filename
[filenameLength
-1]!=U_FILE_SEP_CHAR
&&
87 filename
[filenameLength
-1]!=U_FILE_ALT_SEP_CHAR
) {
88 filename
.append(U_FILE_SEP_CHAR
, errorCode
);
90 filename
.append(U_ICUDATA_NAME
, errorCode
);
91 filename
.append(".dat", errorCode
);
92 pkg
.readPackage(filename
.data());
96 virtual ~PackageLookup() {}
98 // virtual void call(UErrorCode* pErrorCode) { ... }
100 virtual long getOperationsPerIteration() {
101 return pkg
.getItemCount();
104 // virtual long getEventsPerIteration();
111 int32_t nameOffset
, dataOffset
;
114 // Similar to ICU 4.6 offsetTOCLookupFn() (in ucmndata.c).
115 static int32_t simpleBinarySearch(const char *s
, const char *names
, const TOCEntry
*toc
, int32_t count
) {
118 int32_t lastNumber
=limit
;
120 int32_t number
=(start
+limit
)/2;
121 if(lastNumber
==number
) { // have we moved?
122 return -1; // not found
125 int32_t cmp
=strcmp(s
, names
+toc
[number
].nameOffset
);
136 class BinarySearchPackageLookup
: public PackageLookup
{
138 BinarySearchPackageLookup(const DictionaryTriePerfTest
&perf
)
139 : PackageLookup(perf
) {
140 IcuToolErrorCode
errorCode("BinarySearchPackageLookup()");
141 int32_t count
=pkg
.getItemCount();
142 toc
=new TOCEntry
[count
];
143 for(int32_t i
=0; i
<count
; ++i
) {
144 toc
[i
].nameOffset
=itemNames
.length();
145 toc
[i
].dataOffset
=i
; // arbitrary value, see toc comment below
146 // The Package class removes the "icudt46l/" prefix.
147 // We restore that here for a fair performance test.
148 const char *name
=pkg
.getItem(i
)->name
;
149 itemNames
.append("icudt46l/", errorCode
);
150 itemNames
.append(name
, strlen(name
)+1, errorCode
);
152 printf("size of item names: %6ld\n", (long)itemNames
.length());
153 printf("size of TOC: %6ld\n", (long)(count
*8));
154 printf("total index size: %6ld\n", (long)(itemNames
.length()+count
*8));
156 virtual ~BinarySearchPackageLookup() {
160 virtual void call(UErrorCode
* /*pErrorCode*/) {
161 int32_t count
=pkg
.getItemCount();
162 const char *itemNameChars
=itemNames
.data();
163 const char *name
=itemNameChars
;
164 for(int32_t i
=0; i
<count
; ++i
) {
165 if(simpleBinarySearch(name
, itemNameChars
, toc
, count
)<0) {
166 fprintf(stderr
, "item not found: %s\n", name
);
168 name
=strchr(name
, 0)+1;
173 CharString itemNames
;
174 // toc imitates a .dat file's array of UDataOffsetTOCEntry
175 // with nameOffset and dataOffset.
176 // We don't need the dataOffsets, but we want to imitate the real
177 // memory density, to measure equivalent CPU cache usage.
182 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
185 // Compare strings where we know the shared prefix length,
186 // and advance the prefix length as we find that the strings share even more characters.
187 static int32_t strcmpAfterPrefix(const char *s1
, const char *s2
, int32_t &prefixLength
) {
188 int32_t pl
=prefixLength
;
193 int32_t c1
=(uint8_t)*s1
++;
194 int32_t c2
=(uint8_t)*s2
++;
196 if(cmp
!=0 || c1
==0) { // different or done
199 ++pl
; // increment shared same-prefix length
205 static int32_t prefixBinarySearch(const char *s
, const char *names
, const TOCEntry
*toc
, int32_t count
) {
211 // Remember the shared prefix between s, start and limit,
212 // and don't compare that shared prefix again.
213 // The shared prefix should get longer as we narrow the [start, limit[ range.
214 int32_t startPrefixLength
=0;
215 int32_t limitPrefixLength
=0;
216 // Prime the prefix lengths so that we don't keep prefixLength at 0 until
217 // both the start and limit indexes have moved.
218 // At the same time, we find if s is one of the start and (limit-1) names,
219 // and if not, exclude them from the actual binary search.
220 if(0==strcmpAfterPrefix(s
, names
+toc
[0].nameOffset
, startPrefixLength
)) {
225 if(0==strcmpAfterPrefix(s
, names
+toc
[limit
].nameOffset
, limitPrefixLength
)) {
229 int32_t i
=(start
+limit
)/2;
230 int32_t prefixLength
=MIN(startPrefixLength
, limitPrefixLength
);
231 int32_t cmp
=strcmpAfterPrefix(s
, names
+toc
[i
].nameOffset
, prefixLength
);
234 limitPrefixLength
=prefixLength
;
239 startPrefixLength
=prefixLength
;
245 class PrefixBinarySearchPackageLookup
: public BinarySearchPackageLookup
{
247 PrefixBinarySearchPackageLookup(const DictionaryTriePerfTest
&perf
)
248 : BinarySearchPackageLookup(perf
) {}
250 virtual void call(UErrorCode
* /*pErrorCode*/) {
251 int32_t count
=pkg
.getItemCount();
252 const char *itemNameChars
=itemNames
.data();
253 const char *name
=itemNameChars
;
254 for(int32_t i
=0; i
<count
; ++i
) {
255 if(prefixBinarySearch(name
, itemNameChars
, toc
, count
)<0) {
256 fprintf(stderr
, "item not found: %s\n", name
);
258 name
=strchr(name
, 0)+1;
263 static int32_t bytesTrieLookup(const char *s
, const char *nameTrieBytes
) {
264 BytesTrie
trie(nameTrieBytes
);
265 if(USTRINGTRIE_HAS_VALUE(trie
.next(s
, -1))) {
266 return trie
.getValue();
272 class BytesTriePackageLookup
: public PackageLookup
{
274 BytesTriePackageLookup(const DictionaryTriePerfTest
&perf
)
275 : PackageLookup(perf
) {
276 IcuToolErrorCode
errorCode("BinarySearchPackageLookup()");
277 builder
=new BytesTrieBuilder(errorCode
);
278 int32_t count
=pkg
.getItemCount();
279 for(int32_t i
=0; i
<count
; ++i
) {
280 // The Package class removes the "icudt46l/" prefix.
281 // We restore that here for a fair performance test.
282 // We store all full names so that we do not have to reconstruct them
283 // in the call() function.
284 const char *name
=pkg
.getItem(i
)->name
;
285 int32_t offset
=itemNames
.length();
286 itemNames
.append("icudt46l/", errorCode
);
287 itemNames
.append(name
, -1, errorCode
);
288 // As value, set the data item index.
289 // In a real implementation, we would use that to get the
290 // start and limit offset of the data item.
291 StringPiece
fullName(itemNames
.toStringPiece());
292 fullName
.remove_prefix(offset
);
293 builder
->add(fullName
, i
, errorCode
);
294 // NUL-terminate the name for call() to find the next one.
295 itemNames
.append(0, errorCode
);
297 int32_t length
=builder
->buildStringPiece(USTRINGTRIE_BUILD_SMALL
, errorCode
).length();
298 printf("size of BytesTrie: %6ld\n", (long)length
);
299 // count+1: +1 for the last-item limit offset which we should have always had
300 printf("size of dataOffsets:%6ld\n", (long)((count
+1)*4));
301 printf("total index size: %6ld\n", (long)(length
+(count
+1)*4));
303 virtual ~BytesTriePackageLookup() {
307 virtual void call(UErrorCode
*pErrorCode
) {
308 int32_t count
=pkg
.getItemCount();
309 const char *nameTrieBytes
=builder
->buildStringPiece(USTRINGTRIE_BUILD_SMALL
, *pErrorCode
).data();
310 const char *name
=itemNames
.data();
311 for(int32_t i
=0; i
<count
; ++i
) {
312 if(bytesTrieLookup(name
, nameTrieBytes
)<0) {
313 fprintf(stderr
, "item not found: %s\n", name
);
315 name
=strchr(name
, 0)+1;
320 BytesTrieBuilder
*builder
;
321 CharString itemNames
;
324 // Performance test function object.
325 // Each subclass loads a dictionary text file
326 // from the -s or --sourcedir path plus -f or --file-name.
327 // For example, <ICU source dir>/source/data/brkitr/thaidict.txt.
328 class DictLookup
: public UPerfFunction
{
330 DictLookup(const DictionaryTriePerfTest
&perfTest
) : perf(perfTest
) {}
332 virtual long getOperationsPerIteration() {
333 return perf
.numTextLines
;
337 const DictionaryTriePerfTest
&perf
;
340 class CompactTrieDictLookup
: public DictLookup
{
342 CompactTrieDictLookup(const DictionaryTriePerfTest
&perfTest
)
343 : DictLookup(perfTest
), ctd(NULL
) {
344 IcuToolErrorCode
errorCode("UCharsTrieDictLookup()");
345 // U+0E1C is the median code unit, from
346 // the UCharsTrie root node (split-branch node) for thaidict.txt.
347 MutableTrieDictionary
builder(0xe1c, errorCode
);
348 const ULine
*lines
=perf
.getCachedLines();
349 int32_t numLines
=perf
.getNumLines();
350 for(int32_t i
=0; i
<numLines
; ++i
) {
351 // Skip comment lines (start with a character below 'A').
352 if(lines
[i
].name
[0]<0x41) {
355 builder
.addWord(lines
[i
].name
, lines
[i
].len
, errorCode
);
357 ctd
=new CompactTrieDictionary(builder
, errorCode
);
358 int32_t length
=(int32_t)ctd
->dataSize();
359 printf("size of CompactTrieDict: %6ld bytes\n", (long)length
);
362 virtual ~CompactTrieDictLookup() {
366 virtual void call(UErrorCode
*pErrorCode
) {
367 UText text
=UTEXT_INITIALIZER
;
369 const ULine
*lines
=perf
.getCachedLines();
370 int32_t numLines
=perf
.getNumLines();
371 for(int32_t i
=0; i
<numLines
; ++i
) {
372 // Skip comment lines (start with a character below 'A').
373 if(lines
[i
].name
[0]<0x41) {
376 utext_openUChars(&text
, lines
[i
].name
, lines
[i
].len
, pErrorCode
);
378 ctd
->matches(&text
, lines
[i
].len
,
379 lengths
, count
, LENGTHOF(lengths
));
380 if(count
==0 || lengths
[count
-1]!=lines
[i
].len
) {
381 fprintf(stderr
, "word %ld (0-based) not found\n", (long)i
);
387 CompactTrieDictionary
*ctd
;
390 // Closely imitate CompactTrieDictionary::matches().
391 // Note: CompactTrieDictionary::matches() is part of its trie implementation,
392 // and while it loops over the text, it knows the current state.
393 // By contrast, this implementation uses UCharsTrie API functions that have to
394 // check the trie state each time and load/store state in the object.
395 // (Whether it hasNext() and whether it is in the middle of a linear-match node.)
397 ucharsTrieMatches(UCharsTrie
&trie
,
398 UText
*text
, int32_t textLimit
,
399 int32_t *lengths
, int &count
, int limit
) {
400 UChar32 c
=utext_next32(text
);
402 // a) CompactTrieDictionary::matches() does not check for U_SENTINEL.
403 // b) It also ignores non-BMP code points by casting to UChar!
407 // Should be firstForCodePoint() but CompactTrieDictionary
408 // handles only code units.
409 UStringTrieResult result
=trie
.first(c
);
413 if(USTRINGTRIE_HAS_VALUE(result
)) {
415 // lengths[count++]=(int32_t)utext_getNativeIndex(text);
416 lengths
[count
++]=numChars
; // CompactTrieDictionary just counts chars too.
418 if(result
==USTRINGTRIE_FINAL_VALUE
) {
421 } else if(result
==USTRINGTRIE_NO_MATCH
) {
424 if(numChars
>=textLimit
) {
425 // Note: Why do we have both a text limit and a UText that knows its length?
428 UChar32 c
=utext_next32(text
);
430 // a) CompactTrieDictionary::matches() does not check for U_SENTINEL.
431 // b) It also ignores non-BMP code points by casting to UChar!
436 // Should be nextForCodePoint() but CompactTrieDictionary
437 // handles only code units.
441 // Note: CompactTrieDictionary::matches() comments say that it leaves the UText
442 // after the longest prefix match and returns the number of characters
443 // that were matched.
444 if(index
!=lastMatch
) {
445 utext_setNativeIndex(text
, lastMatch
);
447 return lastMatch
-start
;
448 // However, it does not do either of these, so I am not trying to
449 // imitate it (or its docs) 100%.
454 class UCharsTrieDictLookup
: public DictLookup
{
456 UCharsTrieDictLookup(const DictionaryTriePerfTest
&perfTest
)
457 : DictLookup(perfTest
), trie(NULL
) {
458 IcuToolErrorCode
errorCode("UCharsTrieDictLookup()");
459 builder
=new UCharsTrieBuilder(errorCode
);
460 const ULine
*lines
=perf
.getCachedLines();
461 int32_t numLines
=perf
.getNumLines();
462 for(int32_t i
=0; i
<numLines
; ++i
) {
463 // Skip comment lines (start with a character below 'A').
464 if(lines
[i
].name
[0]<0x41) {
467 builder
->add(UnicodeString(FALSE
, lines
[i
].name
, lines
[i
].len
), 0, errorCode
);
469 UnicodeString trieUChars
;
470 int32_t length
=builder
->buildUnicodeString(USTRINGTRIE_BUILD_SMALL
, trieUChars
, errorCode
).length();
471 printf("size of UCharsTrie: %6ld bytes\n", (long)length
*2);
472 trie
=builder
->build(USTRINGTRIE_BUILD_SMALL
, errorCode
);
475 virtual ~UCharsTrieDictLookup() {
481 UCharsTrieBuilder
*builder
;
485 class UCharsTrieDictMatches
: public UCharsTrieDictLookup
{
487 UCharsTrieDictMatches(const DictionaryTriePerfTest
&perfTest
)
488 : UCharsTrieDictLookup(perfTest
) {}
490 virtual void call(UErrorCode
*pErrorCode
) {
491 UText text
=UTEXT_INITIALIZER
;
493 const ULine
*lines
=perf
.getCachedLines();
494 int32_t numLines
=perf
.getNumLines();
495 for(int32_t i
=0; i
<numLines
; ++i
) {
496 // Skip comment lines (start with a character below 'A').
497 if(lines
[i
].name
[0]<0x41) {
500 utext_openUChars(&text
, lines
[i
].name
, lines
[i
].len
, pErrorCode
);
502 ucharsTrieMatches(*trie
, &text
, lines
[i
].len
,
503 lengths
, count
, LENGTHOF(lengths
));
504 if(count
==0 || lengths
[count
-1]!=lines
[i
].len
) {
505 fprintf(stderr
, "word %ld (0-based) not found\n", (long)i
);
511 class UCharsTrieDictContains
: public UCharsTrieDictLookup
{
513 UCharsTrieDictContains(const DictionaryTriePerfTest
&perfTest
)
514 : UCharsTrieDictLookup(perfTest
) {}
516 virtual void call(UErrorCode
* /*pErrorCode*/) {
517 const ULine
*lines
=perf
.getCachedLines();
518 int32_t numLines
=perf
.getNumLines();
519 for(int32_t i
=0; i
<numLines
; ++i
) {
520 // Skip comment lines (which start with a character below 'A').
521 if(lines
[i
].name
[0]<0x41) {
524 if(!USTRINGTRIE_HAS_VALUE(trie
->reset().next(lines
[i
].name
, lines
[i
].len
))) {
525 fprintf(stderr
, "word %ld (0-based) not found\n", (long)i
);
531 static inline int32_t thaiCharToByte(UChar32 c
) {
532 if(0xe00<=c
&& c
<=0xefe) {
541 static UBool
thaiWordToBytes(const UChar
*s
, int32_t length
,
542 CharString
&str
, UErrorCode
&errorCode
) {
543 for(int32_t i
=0; i
<length
; ++i
) {
545 int32_t b
=thaiCharToByte(c
);
547 str
.append((char)b
, errorCode
);
549 fprintf(stderr
, "thaiWordToBytes(): unable to encode U+%04X as a byte\n", c
);
556 class BytesTrieDictLookup
: public DictLookup
{
558 BytesTrieDictLookup(const DictionaryTriePerfTest
&perfTest
)
559 : DictLookup(perfTest
), trie(NULL
), noDict(FALSE
) {
560 IcuToolErrorCode
errorCode("BytesTrieDictLookup()");
561 builder
=new BytesTrieBuilder(errorCode
);
563 const ULine
*lines
=perf
.getCachedLines();
564 int32_t numLines
=perf
.getNumLines();
565 for(int32_t i
=0; i
<numLines
; ++i
) {
566 // Skip comment lines (start with a character below 'A').
567 if(lines
[i
].name
[0]<0x41) {
570 if(!thaiWordToBytes(lines
[i
].name
, lines
[i
].len
, str
.clear(), errorCode
)) {
571 fprintf(stderr
, "thaiWordToBytes(): failed for word %ld (0-based)\n", (long)i
);
575 builder
->add(str
.toStringPiece(), 0, errorCode
);
578 int32_t length
=builder
->buildStringPiece(USTRINGTRIE_BUILD_SMALL
, errorCode
).length();
579 printf("size of BytesTrie: %6ld bytes\n", (long)length
);
580 trie
=builder
->build(USTRINGTRIE_BUILD_SMALL
, errorCode
);
584 virtual ~BytesTrieDictLookup() {
590 BytesTrieBuilder
*builder
;
596 bytesTrieMatches(BytesTrie
&trie
,
597 UText
*text
, int32_t textLimit
,
598 int32_t *lengths
, int &count
, int limit
) {
599 UChar32 c
=utext_next32(text
);
603 UStringTrieResult result
=trie
.first(thaiCharToByte(c
));
607 if(USTRINGTRIE_HAS_VALUE(result
)) {
609 // lengths[count++]=(int32_t)utext_getNativeIndex(text);
610 lengths
[count
++]=numChars
; // CompactTrieDictionary just counts chars too.
612 if(result
==USTRINGTRIE_FINAL_VALUE
) {
615 } else if(result
==USTRINGTRIE_NO_MATCH
) {
618 if(numChars
>=textLimit
) {
621 UChar32 c
=utext_next32(text
);
626 result
=trie
.next(thaiCharToByte(c
));
631 class BytesTrieDictMatches
: public BytesTrieDictLookup
{
633 BytesTrieDictMatches(const DictionaryTriePerfTest
&perfTest
)
634 : BytesTrieDictLookup(perfTest
) {}
636 virtual void call(UErrorCode
*pErrorCode
) {
640 UText text
=UTEXT_INITIALIZER
;
642 const ULine
*lines
=perf
.getCachedLines();
643 int32_t numLines
=perf
.getNumLines();
644 for(int32_t i
=0; i
<numLines
; ++i
) {
645 // Skip comment lines (start with a character below 'A').
646 if(lines
[i
].name
[0]<0x41) {
649 utext_openUChars(&text
, lines
[i
].name
, lines
[i
].len
, pErrorCode
);
651 bytesTrieMatches(*trie
, &text
, lines
[i
].len
,
652 lengths
, count
, LENGTHOF(lengths
));
653 if(count
==0 || lengths
[count
-1]!=lines
[i
].len
) {
654 fprintf(stderr
, "word %ld (0-based) not found\n", (long)i
);
660 class BytesTrieDictContains
: public BytesTrieDictLookup
{
662 BytesTrieDictContains(const DictionaryTriePerfTest
&perfTest
)
663 : BytesTrieDictLookup(perfTest
) {}
665 virtual void call(UErrorCode
* /*pErrorCode*/) {
669 const ULine
*lines
=perf
.getCachedLines();
670 int32_t numLines
=perf
.getNumLines();
671 for(int32_t i
=0; i
<numLines
; ++i
) {
672 const UChar
*line
=lines
[i
].name
;
673 // Skip comment lines (start with a character below 'A').
677 UStringTrieResult result
=trie
->first(thaiCharToByte(line
[0]));
678 int32_t lineLength
=lines
[i
].len
;
679 for(int32_t j
=1; j
<lineLength
; ++j
) {
680 if(!USTRINGTRIE_HAS_NEXT(result
)) {
681 fprintf(stderr
, "word %ld (0-based) not found\n", (long)i
);
684 result
=trie
->next(thaiCharToByte(line
[j
]));
686 if(!USTRINGTRIE_HAS_VALUE(result
)) {
687 fprintf(stderr
, "word %ld (0-based) not found\n", (long)i
);
693 UPerfFunction
*DictionaryTriePerfTest::runIndexedTest(int32_t index
, UBool exec
,
694 const char *&name
, char * /*par*/) {
698 name
="compacttriematches";
700 return new CompactTrieDictLookup(*this);
704 name
="ucharstriematches";
706 return new UCharsTrieDictMatches(*this);
710 name
="ucharstriecontains";
712 return new UCharsTrieDictContains(*this);
716 name
="bytestriematches";
718 return new BytesTrieDictMatches(*this);
722 name
="bytestriecontains";
724 return new BytesTrieDictContains(*this);
732 if(index
==0 && exec
) {
733 puts("Running BytesTrie perf tests on the .dat package file from the --sourcedir.\n"
734 "For UCharsTrie perf tests on a dictionary text file, specify the -f or --file-name.\n");
738 name
="simplebinarysearch";
740 return new BinarySearchPackageLookup(*this);
744 name
="prefixbinarysearch";
746 return new PrefixBinarySearchPackageLookup(*this);
752 return new BytesTriePackageLookup(*this);
763 int main(int argc
, const char *argv
[]) {
764 IcuToolErrorCode
errorCode("dicttrieperf main()");
765 DictionaryTriePerfTest
test(argc
, argv
, errorCode
);
766 if(errorCode
.isFailure()) {
767 fprintf(stderr
, "DictionaryTriePerfTest() failed: %s\n", errorCode
.errorName());
769 return errorCode
.reset();
772 fprintf(stderr
, "FAILED: Tests could not be run, please check the arguments.\n");