Bench.cpp (86837B)
1 // Bench.cpp 2 3 #include "StdAfx.h" 4 5 #include <stdio.h> 6 7 #ifndef _WIN32 8 #define USE_POSIX_TIME 9 #define USE_POSIX_TIME2 10 #endif 11 12 #ifdef USE_POSIX_TIME 13 #include <time.h> 14 #ifdef USE_POSIX_TIME2 15 #include <sys/time.h> 16 #endif 17 #endif 18 19 #ifdef _WIN32 20 #define USE_ALLOCA 21 #endif 22 23 #ifdef USE_ALLOCA 24 #ifdef _WIN32 25 #include <malloc.h> 26 #else 27 #include <stdlib.h> 28 #endif 29 #endif 30 31 #include "../../../../C/7zCrc.h" 32 #include "../../../../C/Alloc.h" 33 #include "../../../../C/CpuArch.h" 34 35 #ifndef _7ZIP_ST 36 #include "../../../Windows/Synchronization.h" 37 #include "../../../Windows/Thread.h" 38 #endif 39 40 #if defined(_WIN32) || defined(UNIX_USE_WIN_FILE) 41 #define USE_WIN_FILE 42 #endif 43 44 #ifdef USE_WIN_FILE 45 #include "../../../Windows/FileIO.h" 46 #endif 47 48 49 #include "../../../Common/IntToString.h" 50 #include "../../../Common/StringConvert.h" 51 #include "../../../Common/StringToInt.h" 52 53 #include "../../Common/MethodProps.h" 54 #include "../../Common/StreamUtils.h" 55 56 #include "Bench.h" 57 58 using namespace NWindows; 59 60 static const UInt32 k_LZMA = 0x030101; 61 62 static const UInt64 kComplexInCommands = (UInt64)1 << 63 #ifdef UNDER_CE 64 31; 65 #else 66 34; 67 #endif 68 69 static const UInt32 kComplexInSeconds = 4; 70 71 static void SetComplexCommands(UInt32 complexInSeconds, 72 bool isSpecifiedFreq, UInt64 cpuFreq, UInt64 &complexInCommands) 73 { 74 complexInCommands = kComplexInCommands; 75 const UInt64 kMinFreq = (UInt64)1000000 * 4; 76 const UInt64 kMaxFreq = (UInt64)1000000 * 20000; 77 if (cpuFreq < kMinFreq && !isSpecifiedFreq) 78 cpuFreq = kMinFreq; 79 if (cpuFreq < kMaxFreq || isSpecifiedFreq) 80 { 81 if (complexInSeconds != 0) 82 complexInCommands = complexInSeconds * cpuFreq; 83 else 84 complexInCommands = cpuFreq >> 2; 85 } 86 } 87 88 static const unsigned kNumHashDictBits = 17; 89 static const UInt32 kFilterUnpackSize = (48 << 10); 90 91 static const unsigned kOldLzmaDictBits = 30; 92 93 static const UInt32 kAdditionalSize = (1 << 16); 94 static const UInt32 kCompressedAdditionalSize = (1 << 10); 95 static const UInt32 kMaxLzmaPropSize = 5; 96 97 class CBaseRandomGenerator 98 { 99 UInt32 A1; 100 UInt32 A2; 101 public: 102 CBaseRandomGenerator() { Init(); } 103 void Init() { A1 = 362436069; A2 = 521288629;} 104 UInt32 GetRnd() 105 { 106 return 107 ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) + 108 ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) ); 109 } 110 }; 111 112 113 static const unsigned kBufferAlignment = 1 << 4; 114 115 struct CBenchBuffer 116 { 117 size_t BufferSize; 118 119 #ifdef _WIN32 120 121 Byte *Buffer; 122 123 CBenchBuffer(): BufferSize(0), Buffer(NULL) {} 124 ~CBenchBuffer() { ::MidFree(Buffer); } 125 126 void AllocAlignedMask(size_t size, size_t) 127 { 128 ::MidFree(Buffer); 129 BufferSize = 0; 130 Buffer = (Byte *)::MidAlloc(size); 131 if (Buffer) 132 BufferSize = size; 133 } 134 135 #else 136 137 Byte *Buffer; 138 Byte *_bufBase; 139 140 CBenchBuffer(): BufferSize(0), Buffer(NULL), _bufBase(NULL){} 141 ~CBenchBuffer() { ::MidFree(_bufBase); } 142 143 void AllocAlignedMask(size_t size, size_t alignMask) 144 { 145 ::MidFree(_bufBase); 146 Buffer = NULL; 147 BufferSize = 0; 148 _bufBase = (Byte *)::MidAlloc(size + alignMask); 149 150 if (_bufBase) 151 { 152 // Buffer = (Byte *)(((uintptr_t)_bufBase + alignMask) & ~(uintptr_t)alignMask); 153 Buffer = (Byte *)(((ptrdiff_t)_bufBase + alignMask) & ~(ptrdiff_t)alignMask); 154 BufferSize = size; 155 } 156 } 157 158 #endif 159 160 bool Alloc(size_t size) 161 { 162 if (Buffer && BufferSize == size) 163 return true; 164 AllocAlignedMask(size, kBufferAlignment - 1); 165 return (Buffer != NULL || size == 0); 166 } 167 }; 168 169 170 class CBenchRandomGenerator: public CBenchBuffer 171 { 172 static UInt32 GetVal(UInt32 &res, unsigned numBits) 173 { 174 UInt32 val = res & (((UInt32)1 << numBits) - 1); 175 res >>= numBits; 176 return val; 177 } 178 179 static UInt32 GetLen(UInt32 &r) 180 { 181 UInt32 len = GetVal(r, 2); 182 return GetVal(r, 1 + len); 183 } 184 185 public: 186 187 void GenerateSimpleRandom(CBaseRandomGenerator *_RG_) 188 { 189 CBaseRandomGenerator rg = *_RG_; 190 const size_t bufSize = BufferSize; 191 Byte *buf = Buffer; 192 for (size_t i = 0; i < bufSize; i++) 193 buf[i] = (Byte)rg.GetRnd(); 194 *_RG_ = rg; 195 } 196 197 void GenerateLz(unsigned dictBits, CBaseRandomGenerator *_RG_) 198 { 199 CBaseRandomGenerator rg = *_RG_; 200 UInt32 pos = 0; 201 UInt32 rep0 = 1; 202 const size_t bufSize = BufferSize; 203 Byte *buf = Buffer; 204 unsigned posBits = 1; 205 206 while (pos < bufSize) 207 { 208 UInt32 r = rg.GetRnd(); 209 if (GetVal(r, 1) == 0 || pos < 1024) 210 buf[pos++] = (Byte)(r & 0xFF); 211 else 212 { 213 UInt32 len; 214 len = 1 + GetLen(r); 215 216 if (GetVal(r, 3) != 0) 217 { 218 len += GetLen(r); 219 220 while (((UInt32)1 << posBits) < pos) 221 posBits++; 222 223 unsigned numBitsMax = dictBits; 224 if (numBitsMax > posBits) 225 numBitsMax = posBits; 226 227 const unsigned kAddBits = 6; 228 unsigned numLogBits = 5; 229 if (numBitsMax <= (1 << 4) - 1 + kAddBits) 230 numLogBits = 4; 231 232 for (;;) 233 { 234 UInt32 ppp = GetVal(r, numLogBits) + kAddBits; 235 r = rg.GetRnd(); 236 if (ppp > numBitsMax) 237 continue; 238 rep0 = GetVal(r, ppp); 239 if (rep0 < pos) 240 break; 241 r = rg.GetRnd(); 242 } 243 rep0++; 244 } 245 246 { 247 UInt32 rem = (UInt32)bufSize - pos; 248 if (len > rem) 249 len = rem; 250 } 251 Byte *dest = buf + pos; 252 const Byte *src = dest - rep0; 253 pos += len; 254 for (UInt32 i = 0; i < len; i++) 255 *dest++ = *src++; 256 } 257 } 258 259 *_RG_ = rg; 260 } 261 }; 262 263 264 class CBenchmarkInStream: 265 public ISequentialInStream, 266 public CMyUnknownImp 267 { 268 const Byte *Data; 269 size_t Pos; 270 size_t Size; 271 public: 272 MY_UNKNOWN_IMP 273 void Init(const Byte *data, size_t size) 274 { 275 Data = data; 276 Size = size; 277 Pos = 0; 278 } 279 STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); 280 }; 281 282 STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 283 { 284 size_t remain = Size - Pos; 285 UInt32 kMaxBlockSize = (1 << 20); 286 if (size > kMaxBlockSize) 287 size = kMaxBlockSize; 288 if (size > remain) 289 size = (UInt32)remain; 290 for (UInt32 i = 0; i < size; i++) 291 ((Byte *)data)[i] = Data[Pos + i]; 292 Pos += size; 293 if (processedSize) 294 *processedSize = size; 295 return S_OK; 296 } 297 298 class CBenchmarkOutStream: 299 public ISequentialOutStream, 300 public CBenchBuffer, 301 public CMyUnknownImp 302 { 303 // bool _overflow; 304 public: 305 size_t Pos; 306 bool RealCopy; 307 bool CalcCrc; 308 UInt32 Crc; 309 310 // CBenchmarkOutStream(): _overflow(false) {} 311 void Init(bool realCopy, bool calcCrc) 312 { 313 Crc = CRC_INIT_VAL; 314 RealCopy = realCopy; 315 CalcCrc = calcCrc; 316 // _overflow = false; 317 Pos = 0; 318 } 319 320 // void Print() { printf("\n%8d %8d\n", (unsigned)BufferSize, (unsigned)Pos); } 321 322 MY_UNKNOWN_IMP 323 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); 324 }; 325 326 STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 327 { 328 size_t curSize = BufferSize - Pos; 329 if (curSize > size) 330 curSize = size; 331 if (curSize != 0) 332 { 333 if (RealCopy) 334 memcpy(Buffer + Pos, data, curSize); 335 if (CalcCrc) 336 Crc = CrcUpdate(Crc, data, curSize); 337 Pos += curSize; 338 } 339 if (processedSize) 340 *processedSize = (UInt32)curSize; 341 if (curSize != size) 342 { 343 // _overflow = true; 344 return E_FAIL; 345 } 346 return S_OK; 347 } 348 349 class CCrcOutStream: 350 public ISequentialOutStream, 351 public CMyUnknownImp 352 { 353 public: 354 bool CalcCrc; 355 UInt32 Crc; 356 MY_UNKNOWN_IMP 357 358 CCrcOutStream(): CalcCrc(true) {}; 359 void Init() { Crc = CRC_INIT_VAL; } 360 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); 361 }; 362 363 STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 364 { 365 if (CalcCrc) 366 Crc = CrcUpdate(Crc, data, size); 367 if (processedSize) 368 *processedSize = size; 369 return S_OK; 370 } 371 372 static UInt64 GetTimeCount() 373 { 374 #ifdef USE_POSIX_TIME 375 #ifdef USE_POSIX_TIME2 376 timeval v; 377 if (gettimeofday(&v, 0) == 0) 378 return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec; 379 return (UInt64)time(NULL) * 1000000; 380 #else 381 return time(NULL); 382 #endif 383 #else 384 /* 385 LARGE_INTEGER value; 386 if (::QueryPerformanceCounter(&value)) 387 return value.QuadPart; 388 */ 389 return GetTickCount(); 390 #endif 391 } 392 393 static UInt64 GetFreq() 394 { 395 #ifdef USE_POSIX_TIME 396 #ifdef USE_POSIX_TIME2 397 return 1000000; 398 #else 399 return 1; 400 #endif 401 #else 402 /* 403 LARGE_INTEGER value; 404 if (::QueryPerformanceFrequency(&value)) 405 return value.QuadPart; 406 */ 407 return 1000; 408 #endif 409 } 410 411 #ifdef USE_POSIX_TIME 412 413 struct CUserTime 414 { 415 UInt64 Sum; 416 clock_t Prev; 417 418 void Init() 419 { 420 Prev = clock(); 421 Sum = 0; 422 } 423 424 UInt64 GetUserTime() 425 { 426 clock_t v = clock(); 427 Sum += v - Prev; 428 Prev = v; 429 return Sum; 430 } 431 }; 432 433 #else 434 435 static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } 436 UInt64 GetWinUserTime() 437 { 438 FILETIME creationTime, exitTime, kernelTime, userTime; 439 if ( 440 #ifdef UNDER_CE 441 ::GetThreadTimes(::GetCurrentThread() 442 #else 443 ::GetProcessTimes(::GetCurrentProcess() 444 #endif 445 , &creationTime, &exitTime, &kernelTime, &userTime) != 0) 446 return GetTime64(userTime) + GetTime64(kernelTime); 447 return (UInt64)GetTickCount() * 10000; 448 } 449 450 struct CUserTime 451 { 452 UInt64 StartTime; 453 454 void Init() { StartTime = GetWinUserTime(); } 455 UInt64 GetUserTime() { return GetWinUserTime() - StartTime; } 456 }; 457 458 #endif 459 460 static UInt64 GetUserFreq() 461 { 462 #ifdef USE_POSIX_TIME 463 return CLOCKS_PER_SEC; 464 #else 465 return 10000000; 466 #endif 467 } 468 469 class CBenchProgressStatus 470 { 471 #ifndef _7ZIP_ST 472 NSynchronization::CCriticalSection CS; 473 #endif 474 public: 475 HRESULT Res; 476 bool EncodeMode; 477 void SetResult(HRESULT res) 478 { 479 #ifndef _7ZIP_ST 480 NSynchronization::CCriticalSectionLock lock(CS); 481 #endif 482 Res = res; 483 } 484 HRESULT GetResult() 485 { 486 #ifndef _7ZIP_ST 487 NSynchronization::CCriticalSectionLock lock(CS); 488 #endif 489 return Res; 490 } 491 }; 492 493 struct CBenchInfoCalc 494 { 495 CBenchInfo BenchInfo; 496 CUserTime UserTime; 497 498 void SetStartTime(); 499 void SetFinishTime(CBenchInfo &dest); 500 }; 501 502 void CBenchInfoCalc::SetStartTime() 503 { 504 BenchInfo.GlobalFreq = GetFreq(); 505 BenchInfo.UserFreq = GetUserFreq(); 506 BenchInfo.GlobalTime = ::GetTimeCount(); 507 BenchInfo.UserTime = 0; 508 UserTime.Init(); 509 } 510 511 void CBenchInfoCalc::SetFinishTime(CBenchInfo &dest) 512 { 513 dest = BenchInfo; 514 dest.GlobalTime = ::GetTimeCount() - BenchInfo.GlobalTime; 515 dest.UserTime = UserTime.GetUserTime(); 516 } 517 518 class CBenchProgressInfo: 519 public ICompressProgressInfo, 520 public CMyUnknownImp, 521 public CBenchInfoCalc 522 { 523 public: 524 CBenchProgressStatus *Status; 525 HRESULT Res; 526 IBenchCallback *Callback; 527 528 CBenchProgressInfo(): Callback(0) {} 529 MY_UNKNOWN_IMP 530 STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); 531 }; 532 533 STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) 534 { 535 HRESULT res = Status->GetResult(); 536 if (res != S_OK) 537 return res; 538 if (!Callback) 539 return res; 540 CBenchInfo info; 541 SetFinishTime(info); 542 if (Status->EncodeMode) 543 { 544 info.UnpackSize = BenchInfo.UnpackSize + *inSize; 545 info.PackSize = BenchInfo.PackSize + *outSize; 546 res = Callback->SetEncodeResult(info, false); 547 } 548 else 549 { 550 info.PackSize = BenchInfo.PackSize + *inSize; 551 info.UnpackSize = BenchInfo.UnpackSize + *outSize; 552 res = Callback->SetDecodeResult(info, false); 553 } 554 if (res != S_OK) 555 Status->SetResult(res); 556 return res; 557 } 558 559 static const unsigned kSubBits = 8; 560 561 static UInt32 GetLogSize(UInt32 size) 562 { 563 for (unsigned i = kSubBits; i < 32; i++) 564 for (UInt32 j = 0; j < (1 << kSubBits); j++) 565 if (size <= (((UInt32)1) << i) + (j << (i - kSubBits))) 566 return (i << kSubBits) + j; 567 return (32 << kSubBits); 568 } 569 570 static void NormalizeVals(UInt64 &v1, UInt64 &v2) 571 { 572 while (v1 > 1000000) 573 { 574 v1 >>= 1; 575 v2 >>= 1; 576 } 577 } 578 579 UInt64 CBenchInfo::GetUsage() const 580 { 581 UInt64 userTime = UserTime; 582 UInt64 userFreq = UserFreq; 583 UInt64 globalTime = GlobalTime; 584 UInt64 globalFreq = GlobalFreq; 585 NormalizeVals(userTime, userFreq); 586 NormalizeVals(globalFreq, globalTime); 587 if (userFreq == 0) 588 userFreq = 1; 589 if (globalTime == 0) 590 globalTime = 1; 591 return userTime * globalFreq * 1000000 / userFreq / globalTime; 592 } 593 594 UInt64 CBenchInfo::GetRatingPerUsage(UInt64 rating) const 595 { 596 UInt64 userTime = UserTime; 597 UInt64 userFreq = UserFreq; 598 UInt64 globalTime = GlobalTime; 599 UInt64 globalFreq = GlobalFreq; 600 NormalizeVals(userFreq, userTime); 601 NormalizeVals(globalTime, globalFreq); 602 if (globalFreq == 0) 603 globalFreq = 1; 604 if (userTime == 0) 605 userTime = 1; 606 return userFreq * globalTime / globalFreq * rating / userTime; 607 } 608 609 static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq) 610 { 611 UInt64 elTime = elapsedTime; 612 NormalizeVals(freq, elTime); 613 if (elTime == 0) 614 elTime = 1; 615 return value * freq / elTime; 616 } 617 618 UInt64 CBenchInfo::GetSpeed(UInt64 numCommands) const 619 { 620 return MyMultDiv64(numCommands, GlobalTime, GlobalFreq); 621 } 622 623 struct CBenchProps 624 { 625 bool LzmaRatingMode; 626 627 UInt32 EncComplex; 628 UInt32 DecComplexCompr; 629 UInt32 DecComplexUnc; 630 631 CBenchProps(): LzmaRatingMode(false) {} 632 void SetLzmaCompexity(); 633 634 UInt64 GeComprCommands(UInt64 unpackSize) 635 { 636 return unpackSize * EncComplex; 637 } 638 639 UInt64 GeDecomprCommands(UInt64 packSize, UInt64 unpackSize) 640 { 641 return (packSize * DecComplexCompr + unpackSize * DecComplexUnc); 642 } 643 644 UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size); 645 UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations); 646 }; 647 648 void CBenchProps::SetLzmaCompexity() 649 { 650 EncComplex = 1200; 651 DecComplexUnc = 4; 652 DecComplexCompr = 190; 653 LzmaRatingMode = true; 654 } 655 656 UInt64 CBenchProps::GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) 657 { 658 if (dictSize < (1 << kBenchMinDicLogSize)) 659 dictSize = (1 << kBenchMinDicLogSize); 660 UInt64 encComplex = EncComplex; 661 if (LzmaRatingMode) 662 { 663 UInt64 t = GetLogSize(dictSize) - (kBenchMinDicLogSize << kSubBits); 664 encComplex = 870 + ((t * t * 5) >> (2 * kSubBits)); 665 } 666 UInt64 numCommands = (UInt64)size * encComplex; 667 return MyMultDiv64(numCommands, elapsedTime, freq); 668 } 669 670 UInt64 CBenchProps::GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) 671 { 672 UInt64 numCommands = (inSize * DecComplexCompr + outSize * DecComplexUnc) * numIterations; 673 return MyMultDiv64(numCommands, elapsedTime, freq); 674 } 675 676 UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) 677 { 678 CBenchProps props; 679 props.SetLzmaCompexity(); 680 return props.GetCompressRating(dictSize, elapsedTime, freq, size); 681 } 682 683 UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) 684 { 685 CBenchProps props; 686 props.SetLzmaCompexity(); 687 return props.GetDecompressRating(elapsedTime, freq, outSize, inSize, numIterations); 688 } 689 690 struct CEncoderInfo; 691 692 struct CEncoderInfo 693 { 694 #ifndef _7ZIP_ST 695 NWindows::CThread thread[2]; 696 UInt32 NumDecoderSubThreads; 697 #endif 698 CMyComPtr<ICompressCoder> _encoder; 699 CMyComPtr<ICompressFilter> _encoderFilter; 700 CBenchProgressInfo *progressInfoSpec[2]; 701 CMyComPtr<ICompressProgressInfo> progressInfo[2]; 702 UInt64 NumIterations; 703 704 #ifdef USE_ALLOCA 705 size_t AllocaSize; 706 #endif 707 708 Byte _key[32]; 709 Byte _iv[16]; 710 Byte _psw[16]; 711 bool CheckCrc_Enc; 712 bool CheckCrc_Dec; 713 714 struct CDecoderInfo 715 { 716 CEncoderInfo *Encoder; 717 UInt32 DecoderIndex; 718 bool CallbackMode; 719 720 #ifdef USE_ALLOCA 721 size_t AllocaSize; 722 #endif 723 }; 724 CDecoderInfo decodersInfo[2]; 725 726 CMyComPtr<ICompressCoder> _decoders[2]; 727 CMyComPtr<ICompressFilter> _decoderFilter; 728 729 HRESULT Results[2]; 730 CBenchmarkOutStream *outStreamSpec; 731 CMyComPtr<ISequentialOutStream> outStream; 732 IBenchCallback *callback; 733 IBenchPrintCallback *printCallback; 734 UInt32 crc; 735 size_t kBufferSize; 736 size_t compressedSize; 737 const Byte *uncompressedDataPtr; 738 739 const Byte *fileData; 740 CBenchRandomGenerator rg; 741 742 CBenchBuffer rgCopy; // it must be 16-byte aligned !!! 743 CBenchmarkOutStream *propStreamSpec; 744 CMyComPtr<ISequentialOutStream> propStream; 745 746 // for decode 747 COneMethodInfo _method; 748 size_t _uncompressedDataSize; 749 750 HRESULT Init( 751 const COneMethodInfo &method, 752 unsigned generateDictBits, 753 CBaseRandomGenerator *rg); 754 HRESULT Encode(); 755 HRESULT Decode(UInt32 decoderIndex); 756 757 CEncoderInfo(): 758 fileData(NULL), 759 CheckCrc_Enc(true), 760 CheckCrc_Dec(true), 761 outStreamSpec(0), callback(0), printCallback(0), propStreamSpec(0) {} 762 763 #ifndef _7ZIP_ST 764 765 static THREAD_FUNC_DECL EncodeThreadFunction(void *param) 766 { 767 HRESULT res; 768 CEncoderInfo *encoder = (CEncoderInfo *)param; 769 try 770 { 771 #ifdef USE_ALLOCA 772 alloca(encoder->AllocaSize); 773 #endif 774 775 res = encoder->Encode(); 776 encoder->Results[0] = res; 777 } 778 catch(...) 779 { 780 res = E_FAIL; 781 } 782 if (res != S_OK) 783 encoder->progressInfoSpec[0]->Status->SetResult(res); 784 return 0; 785 } 786 787 static THREAD_FUNC_DECL DecodeThreadFunction(void *param) 788 { 789 CDecoderInfo *decoder = (CDecoderInfo *)param; 790 791 #ifdef USE_ALLOCA 792 alloca(decoder->AllocaSize); 793 #endif 794 795 CEncoderInfo *encoder = decoder->Encoder; 796 encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex); 797 return 0; 798 } 799 800 HRESULT CreateEncoderThread() 801 { 802 return thread[0].Create(EncodeThreadFunction, this); 803 } 804 805 HRESULT CreateDecoderThread(unsigned index, bool callbackMode 806 #ifdef USE_ALLOCA 807 , size_t allocaSize 808 #endif 809 ) 810 { 811 CDecoderInfo &decoder = decodersInfo[index]; 812 decoder.DecoderIndex = index; 813 decoder.Encoder = this; 814 815 #ifdef USE_ALLOCA 816 decoder.AllocaSize = allocaSize; 817 #endif 818 819 decoder.CallbackMode = callbackMode; 820 return thread[index].Create(DecodeThreadFunction, &decoder); 821 } 822 823 #endif 824 }; 825 826 827 HRESULT CEncoderInfo::Init( 828 const COneMethodInfo &method, 829 unsigned generateDictBits, 830 CBaseRandomGenerator *rgLoc) 831 { 832 // we need extra space, if input data is already compressed 833 const size_t kCompressedBufferSize = 834 kCompressedAdditionalSize + 835 kBufferSize + kBufferSize / 16; 836 // kBufferSize / 2; 837 838 if (kCompressedBufferSize < kBufferSize) 839 return E_FAIL; 840 841 uncompressedDataPtr = fileData; 842 843 if (!fileData) 844 { 845 if (!rg.Alloc(kBufferSize)) 846 return E_OUTOFMEMORY; 847 848 // DWORD ttt = GetTickCount(); 849 if (generateDictBits == 0) 850 rg.GenerateSimpleRandom(rgLoc); 851 else 852 rg.GenerateLz(generateDictBits, rgLoc); 853 // printf("\n%d\n ", GetTickCount() - ttt); 854 855 crc = CrcCalc(rg.Buffer, rg.BufferSize); 856 uncompressedDataPtr = rg.Buffer; 857 } 858 859 if (_encoderFilter) 860 { 861 if (!rgCopy.Alloc(kBufferSize)) 862 return E_OUTOFMEMORY; 863 } 864 865 866 outStreamSpec = new CBenchmarkOutStream; 867 outStream = outStreamSpec; 868 if (!outStreamSpec->Alloc(kCompressedBufferSize)) 869 return E_OUTOFMEMORY; 870 871 propStreamSpec = 0; 872 if (!propStream) 873 { 874 propStreamSpec = new CBenchmarkOutStream; 875 propStream = propStreamSpec; 876 } 877 if (!propStreamSpec->Alloc(kMaxLzmaPropSize)) 878 return E_OUTOFMEMORY; 879 propStreamSpec->Init(true, false); 880 881 882 CMyComPtr<IUnknown> coder; 883 if (_encoderFilter) 884 coder = _encoderFilter; 885 else 886 coder = _encoder; 887 { 888 CMyComPtr<ICompressSetCoderProperties> scp; 889 coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); 890 if (scp) 891 { 892 UInt64 reduceSize = kBufferSize; 893 RINOK(method.SetCoderProps(scp, &reduceSize)); 894 } 895 else 896 { 897 if (method.AreThereNonOptionalProps()) 898 return E_INVALIDARG; 899 } 900 901 CMyComPtr<ICompressWriteCoderProperties> writeCoderProps; 902 coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps); 903 if (writeCoderProps) 904 { 905 RINOK(writeCoderProps->WriteCoderProperties(propStream)); 906 } 907 908 { 909 CMyComPtr<ICryptoSetPassword> sp; 910 coder.QueryInterface(IID_ICryptoSetPassword, &sp); 911 if (sp) 912 { 913 RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw))); 914 915 // we must call encoding one time to calculate password key for key cache. 916 // it must be after WriteCoderProperties! 917 Byte temp[16]; 918 memset(temp, 0, sizeof(temp)); 919 920 if (_encoderFilter) 921 { 922 _encoderFilter->Init(); 923 _encoderFilter->Filter(temp, sizeof(temp)); 924 } 925 else 926 { 927 CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; 928 CMyComPtr<ISequentialInStream> inStream = inStreamSpec; 929 inStreamSpec->Init(temp, sizeof(temp)); 930 931 CCrcOutStream *crcStreamSpec = new CCrcOutStream; 932 CMyComPtr<ISequentialOutStream> crcStream = crcStreamSpec; 933 crcStreamSpec->Init(); 934 935 RINOK(_encoder->Code(inStream, crcStream, 0, 0, NULL)); 936 } 937 } 938 } 939 } 940 941 return S_OK; 942 } 943 944 945 static void My_FilterBench(ICompressFilter *filter, Byte *data, size_t size) 946 { 947 while (size != 0) 948 { 949 UInt32 cur = (UInt32)1 << 31; 950 if (cur > size) 951 cur = (UInt32)size; 952 UInt32 processed = filter->Filter(data, cur); 953 data += processed; 954 // if (processed > size) (in AES filter), we must fill last block with zeros. 955 // but it is not important for benchmark. So we just copy that data without filtering. 956 if (processed > size || processed == 0) 957 break; 958 size -= processed; 959 } 960 } 961 962 963 HRESULT CEncoderInfo::Encode() 964 { 965 CBenchInfo &bi = progressInfoSpec[0]->BenchInfo; 966 bi.UnpackSize = 0; 967 bi.PackSize = 0; 968 CMyComPtr<ICryptoProperties> cp; 969 CMyComPtr<IUnknown> coder; 970 if (_encoderFilter) 971 coder = _encoderFilter; 972 else 973 coder = _encoder; 974 coder.QueryInterface(IID_ICryptoProperties, &cp); 975 CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; 976 CMyComPtr<ISequentialInStream> inStream = inStreamSpec; 977 UInt64 prev = 0; 978 979 UInt32 crcPrev = 0; 980 981 if (cp) 982 { 983 RINOK(cp->SetKey(_key, sizeof(_key))); 984 RINOK(cp->SetInitVector(_iv, sizeof(_iv))); 985 } 986 987 for (UInt64 i = 0; i < NumIterations; i++) 988 { 989 if (printCallback && bi.UnpackSize - prev > (1 << 20)) 990 { 991 RINOK(printCallback->CheckBreak()); 992 prev = bi.UnpackSize; 993 } 994 995 bool isLast = (i == NumIterations - 1); 996 bool calcCrc = ((isLast || (i & 0x7F) == 0 || CheckCrc_Enc) && NumIterations != 1); 997 outStreamSpec->Init(isLast, calcCrc); 998 999 if (_encoderFilter) 1000 { 1001 memcpy(rgCopy.Buffer, uncompressedDataPtr, kBufferSize); 1002 _encoderFilter->Init(); 1003 My_FilterBench(_encoderFilter, rgCopy.Buffer, kBufferSize); 1004 RINOK(WriteStream(outStream, rgCopy.Buffer, kBufferSize)); 1005 } 1006 else 1007 { 1008 inStreamSpec->Init(uncompressedDataPtr, kBufferSize); 1009 RINOK(_encoder->Code(inStream, outStream, NULL, NULL, progressInfo[0])); 1010 } 1011 1012 // outStreamSpec->Print(); 1013 1014 UInt32 crcNew = CRC_GET_DIGEST(outStreamSpec->Crc); 1015 if (i == 0) 1016 crcPrev = crcNew; 1017 else if (calcCrc && crcPrev != crcNew) 1018 return E_FAIL; 1019 1020 compressedSize = outStreamSpec->Pos; 1021 bi.UnpackSize += kBufferSize; 1022 bi.PackSize += compressedSize; 1023 } 1024 1025 _encoder.Release(); 1026 _encoderFilter.Release(); 1027 return S_OK; 1028 } 1029 1030 1031 HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) 1032 { 1033 CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; 1034 CMyComPtr<ISequentialInStream> inStream = inStreamSpec; 1035 CMyComPtr<ICompressCoder> &decoder = _decoders[decoderIndex]; 1036 CMyComPtr<IUnknown> coder; 1037 if (_decoderFilter) 1038 { 1039 if (decoderIndex != 0) 1040 return E_FAIL; 1041 coder = _decoderFilter; 1042 } 1043 else 1044 coder = decoder; 1045 1046 CMyComPtr<ICompressSetDecoderProperties2> setDecProps; 1047 coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps); 1048 if (!setDecProps && propStreamSpec->Pos != 0) 1049 return E_FAIL; 1050 1051 CCrcOutStream *crcOutStreamSpec = new CCrcOutStream; 1052 CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec; 1053 1054 CBenchProgressInfo *pi = progressInfoSpec[decoderIndex]; 1055 pi->BenchInfo.UnpackSize = 0; 1056 pi->BenchInfo.PackSize = 0; 1057 1058 #ifndef _7ZIP_ST 1059 { 1060 CMyComPtr<ICompressSetCoderMt> setCoderMt; 1061 coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); 1062 if (setCoderMt) 1063 { 1064 RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads)); 1065 } 1066 } 1067 #endif 1068 1069 CMyComPtr<ICompressSetCoderProperties> scp; 1070 coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); 1071 if (scp) 1072 { 1073 UInt64 reduceSize = _uncompressedDataSize; 1074 RINOK(_method.SetCoderProps(scp, &reduceSize)); 1075 } 1076 1077 CMyComPtr<ICryptoProperties> cp; 1078 coder.QueryInterface(IID_ICryptoProperties, &cp); 1079 1080 if (setDecProps) 1081 { 1082 RINOK(setDecProps->SetDecoderProperties2(propStreamSpec->Buffer, (UInt32)propStreamSpec->Pos)); 1083 } 1084 1085 { 1086 CMyComPtr<ICryptoSetPassword> sp; 1087 coder.QueryInterface(IID_ICryptoSetPassword, &sp); 1088 if (sp) 1089 { 1090 RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw))); 1091 } 1092 } 1093 1094 UInt64 prev = 0; 1095 1096 if (cp) 1097 { 1098 RINOK(cp->SetKey(_key, sizeof(_key))); 1099 RINOK(cp->SetInitVector(_iv, sizeof(_iv))); 1100 } 1101 1102 for (UInt64 i = 0; i < NumIterations; i++) 1103 { 1104 if (printCallback && pi->BenchInfo.UnpackSize - prev > (1 << 20)) 1105 { 1106 RINOK(printCallback->CheckBreak()); 1107 prev = pi->BenchInfo.UnpackSize; 1108 } 1109 1110 inStreamSpec->Init(outStreamSpec->Buffer, compressedSize); 1111 crcOutStreamSpec->Init(); 1112 1113 UInt64 outSize = kBufferSize; 1114 crcOutStreamSpec->CalcCrc = ((i & 0x7F) == 0 || CheckCrc_Dec); 1115 1116 if (_decoderFilter) 1117 { 1118 if (compressedSize > rgCopy.BufferSize) 1119 return E_FAIL; 1120 memcpy(rgCopy.Buffer, outStreamSpec->Buffer, compressedSize); 1121 _decoderFilter->Init(); 1122 My_FilterBench(_decoderFilter, rgCopy.Buffer, compressedSize); 1123 RINOK(WriteStream(crcOutStream, rgCopy.Buffer, compressedSize)); 1124 } 1125 else 1126 { 1127 RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex])); 1128 } 1129 1130 if (crcOutStreamSpec->CalcCrc && CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc) 1131 return S_FALSE; 1132 pi->BenchInfo.UnpackSize += kBufferSize; 1133 pi->BenchInfo.PackSize += compressedSize; 1134 } 1135 1136 decoder.Release(); 1137 _decoderFilter.Release(); 1138 return S_OK; 1139 } 1140 1141 1142 static const UInt32 kNumThreadsMax = (1 << 12); 1143 1144 struct CBenchEncoders 1145 { 1146 CEncoderInfo *encoders; 1147 CBenchEncoders(UInt32 num): encoders(0) { encoders = new CEncoderInfo[num]; } 1148 ~CBenchEncoders() { delete []encoders; } 1149 }; 1150 1151 1152 static UInt64 GetNumIterations(UInt64 numCommands, UInt64 complexInCommands) 1153 { 1154 if (numCommands < (1 << 4)) 1155 numCommands = (1 << 4); 1156 UInt64 res = complexInCommands / numCommands; 1157 return (res == 0 ? 1 : res); 1158 } 1159 1160 1161 static HRESULT MethodBench( 1162 DECL_EXTERNAL_CODECS_LOC_VARS 1163 UInt64 complexInCommands, 1164 bool 1165 #ifndef _7ZIP_ST 1166 oldLzmaBenchMode 1167 #endif 1168 , 1169 UInt32 1170 #ifndef _7ZIP_ST 1171 numThreads 1172 #endif 1173 , 1174 const COneMethodInfo &method2, 1175 size_t uncompressedDataSize, 1176 const Byte *fileData, 1177 unsigned generateDictBits, 1178 1179 IBenchPrintCallback *printCallback, 1180 IBenchCallback *callback, 1181 CBenchProps *benchProps) 1182 { 1183 COneMethodInfo method = method2; 1184 UInt64 methodId; 1185 UInt32 numStreams; 1186 int codecIndex = FindMethod_Index( 1187 EXTERNAL_CODECS_LOC_VARS 1188 method.MethodName, true, 1189 methodId, numStreams); 1190 if (codecIndex < 0) 1191 return E_NOTIMPL; 1192 if (numStreams != 1) 1193 return E_INVALIDARG; 1194 1195 UInt32 numEncoderThreads = 1; 1196 UInt32 numSubDecoderThreads = 1; 1197 1198 #ifndef _7ZIP_ST 1199 numEncoderThreads = numThreads; 1200 1201 if (oldLzmaBenchMode && methodId == k_LZMA) 1202 { 1203 if (numThreads == 1 && method.Get_NumThreads() < 0) 1204 method.AddProp_NumThreads(1); 1205 const UInt32 numLzmaThreads = method.Get_Lzma_NumThreads(); 1206 if (numThreads > 1 && numLzmaThreads > 1) 1207 { 1208 numEncoderThreads = numThreads / 2; 1209 numSubDecoderThreads = 2; 1210 } 1211 } 1212 #endif 1213 1214 CBenchEncoders encodersSpec(numEncoderThreads); 1215 CEncoderInfo *encoders = encodersSpec.encoders; 1216 1217 UInt32 i; 1218 1219 for (i = 0; i < numEncoderThreads; i++) 1220 { 1221 CEncoderInfo &encoder = encoders[i]; 1222 encoder.callback = (i == 0) ? callback : 0; 1223 encoder.printCallback = printCallback; 1224 1225 { 1226 CCreatedCoder cod; 1227 RINOK(CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS codecIndex, true, encoder._encoderFilter, cod)); 1228 encoder._encoder = cod.Coder; 1229 if (!encoder._encoder && !encoder._encoderFilter) 1230 return E_NOTIMPL; 1231 } 1232 1233 encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30 ; 1234 encoder.CheckCrc_Dec = (benchProps->DecComplexCompr + benchProps->DecComplexUnc) > 30 ; 1235 1236 memset(encoder._iv, 0, sizeof(encoder._iv)); 1237 memset(encoder._key, 0, sizeof(encoder._key)); 1238 memset(encoder._psw, 0, sizeof(encoder._psw)); 1239 1240 for (UInt32 j = 0; j < numSubDecoderThreads; j++) 1241 { 1242 CCreatedCoder cod; 1243 CMyComPtr<ICompressCoder> &decoder = encoder._decoders[j]; 1244 RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodId, false, encoder._decoderFilter, cod)); 1245 decoder = cod.Coder; 1246 if (!encoder._decoderFilter && !decoder) 1247 return E_NOTIMPL; 1248 } 1249 } 1250 1251 CBaseRandomGenerator rg; 1252 rg.Init(); 1253 1254 UInt32 crc = 0; 1255 if (fileData) 1256 crc = CrcCalc(fileData, uncompressedDataSize); 1257 1258 for (i = 0; i < numEncoderThreads; i++) 1259 { 1260 CEncoderInfo &encoder = encoders[i]; 1261 encoder._method = method; 1262 encoder._uncompressedDataSize = uncompressedDataSize; 1263 encoder.kBufferSize = uncompressedDataSize; 1264 encoder.fileData = fileData; 1265 encoder.crc = crc; 1266 1267 RINOK(encoders[i].Init(method, generateDictBits, &rg)); 1268 } 1269 1270 CBenchProgressStatus status; 1271 status.Res = S_OK; 1272 status.EncodeMode = true; 1273 1274 for (i = 0; i < numEncoderThreads; i++) 1275 { 1276 CEncoderInfo &encoder = encoders[i]; 1277 encoder.NumIterations = GetNumIterations(benchProps->GeComprCommands(uncompressedDataSize), complexInCommands); 1278 1279 for (int j = 0; j < 2; j++) 1280 { 1281 CBenchProgressInfo *spec = new CBenchProgressInfo; 1282 encoder.progressInfoSpec[j] = spec; 1283 encoder.progressInfo[j] = spec; 1284 spec->Status = &status; 1285 } 1286 1287 if (i == 0) 1288 { 1289 CBenchProgressInfo *bpi = encoder.progressInfoSpec[0]; 1290 bpi->Callback = callback; 1291 bpi->BenchInfo.NumIterations = numEncoderThreads; 1292 bpi->SetStartTime(); 1293 } 1294 1295 #ifndef _7ZIP_ST 1296 if (numEncoderThreads > 1) 1297 { 1298 #ifdef USE_ALLOCA 1299 encoder.AllocaSize = (i * 16 * 21) & 0x7FF; 1300 #endif 1301 1302 RINOK(encoder.CreateEncoderThread()) 1303 } 1304 else 1305 #endif 1306 { 1307 RINOK(encoder.Encode()); 1308 } 1309 } 1310 1311 #ifndef _7ZIP_ST 1312 if (numEncoderThreads > 1) 1313 for (i = 0; i < numEncoderThreads; i++) 1314 encoders[i].thread[0].Wait(); 1315 #endif 1316 1317 RINOK(status.Res); 1318 1319 CBenchInfo info; 1320 1321 encoders[0].progressInfoSpec[0]->SetFinishTime(info); 1322 info.UnpackSize = 0; 1323 info.PackSize = 0; 1324 info.NumIterations = encoders[0].NumIterations; 1325 1326 for (i = 0; i < numEncoderThreads; i++) 1327 { 1328 CEncoderInfo &encoder = encoders[i]; 1329 info.UnpackSize += encoder.kBufferSize; 1330 info.PackSize += encoder.compressedSize; 1331 } 1332 1333 RINOK(callback->SetEncodeResult(info, true)); 1334 1335 1336 status.Res = S_OK; 1337 status.EncodeMode = false; 1338 1339 UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads; 1340 1341 for (i = 0; i < numEncoderThreads; i++) 1342 { 1343 CEncoderInfo &encoder = encoders[i]; 1344 1345 if (i == 0) 1346 { 1347 encoder.NumIterations = GetNumIterations(benchProps->GeDecomprCommands(encoder.compressedSize, encoder.kBufferSize), complexInCommands); 1348 CBenchProgressInfo *bpi = encoder.progressInfoSpec[0]; 1349 bpi->Callback = callback; 1350 bpi->BenchInfo.NumIterations = numDecoderThreads; 1351 bpi->SetStartTime(); 1352 } 1353 else 1354 encoder.NumIterations = encoders[0].NumIterations; 1355 1356 #ifndef _7ZIP_ST 1357 { 1358 int numSubThreads = method.Get_NumThreads(); 1359 encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : numSubThreads; 1360 } 1361 if (numDecoderThreads > 1) 1362 { 1363 for (UInt32 j = 0; j < numSubDecoderThreads; j++) 1364 { 1365 HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0) 1366 #ifdef USE_ALLOCA 1367 , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF 1368 #endif 1369 ); 1370 RINOK(res); 1371 } 1372 } 1373 else 1374 #endif 1375 { 1376 RINOK(encoder.Decode(0)); 1377 } 1378 } 1379 1380 #ifndef _7ZIP_ST 1381 HRESULT res = S_OK; 1382 if (numDecoderThreads > 1) 1383 for (i = 0; i < numEncoderThreads; i++) 1384 for (UInt32 j = 0; j < numSubDecoderThreads; j++) 1385 { 1386 CEncoderInfo &encoder = encoders[i]; 1387 encoder.thread[j].Wait(); 1388 if (encoder.Results[j] != S_OK) 1389 res = encoder.Results[j]; 1390 } 1391 RINOK(res); 1392 #endif 1393 1394 RINOK(status.Res); 1395 encoders[0].progressInfoSpec[0]->SetFinishTime(info); 1396 1397 #ifndef _7ZIP_ST 1398 #ifdef UNDER_CE 1399 if (numDecoderThreads > 1) 1400 for (i = 0; i < numEncoderThreads; i++) 1401 for (UInt32 j = 0; j < numSubDecoderThreads; j++) 1402 { 1403 FILETIME creationTime, exitTime, kernelTime, userTime; 1404 if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0) 1405 info.UserTime += GetTime64(userTime) + GetTime64(kernelTime); 1406 } 1407 #endif 1408 #endif 1409 1410 info.UnpackSize = 0; 1411 info.PackSize = 0; 1412 info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations; 1413 1414 for (i = 0; i < numEncoderThreads; i++) 1415 { 1416 CEncoderInfo &encoder = encoders[i]; 1417 info.UnpackSize += encoder.kBufferSize; 1418 info.PackSize += encoder.compressedSize; 1419 } 1420 1421 RINOK(callback->SetDecodeResult(info, false)); 1422 RINOK(callback->SetDecodeResult(info, true)); 1423 1424 return S_OK; 1425 } 1426 1427 1428 static inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary) 1429 { 1430 UInt32 hs = dictionary - 1; 1431 hs |= (hs >> 1); 1432 hs |= (hs >> 2); 1433 hs |= (hs >> 4); 1434 hs |= (hs >> 8); 1435 hs >>= 1; 1436 hs |= 0xFFFF; 1437 if (hs > (1 << 24)) 1438 hs >>= 1; 1439 hs++; 1440 return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 + 1441 (1 << 20) + (multiThread ? (6 << 20) : 0); 1442 } 1443 1444 UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary, bool totalBench) 1445 { 1446 const UInt32 kBufferSize = dictionary; 1447 const UInt32 kCompressedBufferSize = kBufferSize; // / 2; 1448 bool lzmaMt = (totalBench || numThreads > 1); 1449 UInt32 numBigThreads = numThreads; 1450 if (!totalBench && lzmaMt) 1451 numBigThreads /= 2; 1452 return ((UInt64)kBufferSize + kCompressedBufferSize + 1453 GetLZMAUsage(lzmaMt, dictionary) + (2 << 20)) * numBigThreads; 1454 } 1455 1456 static HRESULT CrcBig(const void *data, UInt32 size, UInt64 numIterations, 1457 const UInt32 *checkSum, IHasher *hf, 1458 IBenchPrintCallback *callback) 1459 { 1460 Byte hash[64]; 1461 UInt64 i; 1462 for (i = 0; i < sizeof(hash); i++) 1463 hash[i] = 0; 1464 for (i = 0; i < numIterations; i++) 1465 { 1466 if (callback && (i & 0xFF) == 0) 1467 { 1468 RINOK(callback->CheckBreak()); 1469 } 1470 hf->Init(); 1471 hf->Update(data, size); 1472 hf->Final(hash); 1473 UInt32 hashSize = hf->GetDigestSize(); 1474 if (hashSize > sizeof(hash)) 1475 return S_FALSE; 1476 UInt32 sum = 0; 1477 for (UInt32 j = 0; j < hashSize; j += 4) 1478 sum ^= GetUi32(hash + j); 1479 if (checkSum && sum != *checkSum) 1480 { 1481 return S_FALSE; 1482 } 1483 } 1484 return S_OK; 1485 } 1486 1487 UInt32 g_BenchCpuFreqTemp = 1; 1488 1489 #define YY1 sum += val; sum ^= val; 1490 #define YY3 YY1 YY1 YY1 YY1 1491 #define YY5 YY3 YY3 YY3 YY3 1492 #define YY7 YY5 YY5 YY5 YY5 1493 static const UInt32 kNumFreqCommands = 128; 1494 1495 EXTERN_C_BEGIN 1496 1497 static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val) 1498 { 1499 for (UInt32 i = 0; i < num; i++) 1500 { 1501 YY7 1502 } 1503 return sum; 1504 } 1505 1506 EXTERN_C_END 1507 1508 1509 #ifndef _7ZIP_ST 1510 1511 struct CFreqInfo 1512 { 1513 NWindows::CThread Thread; 1514 IBenchPrintCallback *Callback; 1515 HRESULT CallbackRes; 1516 UInt32 ValRes; 1517 UInt32 Size; 1518 UInt64 NumIterations; 1519 1520 void Wait() 1521 { 1522 Thread.Wait(); 1523 Thread.Close(); 1524 } 1525 }; 1526 1527 static THREAD_FUNC_DECL FreqThreadFunction(void *param) 1528 { 1529 CFreqInfo *p = (CFreqInfo *)param; 1530 1531 UInt32 sum = g_BenchCpuFreqTemp; 1532 for (UInt64 k = p->NumIterations; k > 0; k--) 1533 { 1534 p->CallbackRes = p->Callback->CheckBreak(); 1535 if (p->CallbackRes != S_OK) 1536 return 0; 1537 sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp); 1538 } 1539 p->ValRes = sum; 1540 return 0; 1541 } 1542 1543 struct CFreqThreads 1544 { 1545 CFreqInfo *Items; 1546 UInt32 NumThreads; 1547 1548 CFreqThreads(): Items(0), NumThreads(0) {} 1549 void WaitAll() 1550 { 1551 for (UInt32 i = 0; i < NumThreads; i++) 1552 Items[i].Wait(); 1553 NumThreads = 0; 1554 } 1555 ~CFreqThreads() 1556 { 1557 WaitAll(); 1558 delete []Items; 1559 } 1560 }; 1561 1562 struct CCrcInfo 1563 { 1564 NWindows::CThread Thread; 1565 IBenchPrintCallback *Callback; 1566 HRESULT CallbackRes; 1567 1568 const Byte *Data; 1569 UInt32 Size; 1570 UInt64 NumIterations; 1571 bool CheckSumDefined; 1572 UInt32 CheckSum; 1573 CMyComPtr<IHasher> Hasher; 1574 HRESULT Res; 1575 1576 #ifdef USE_ALLOCA 1577 size_t AllocaSize; 1578 #endif 1579 1580 void Wait() 1581 { 1582 Thread.Wait(); 1583 Thread.Close(); 1584 } 1585 }; 1586 1587 static THREAD_FUNC_DECL CrcThreadFunction(void *param) 1588 { 1589 CCrcInfo *p = (CCrcInfo *)param; 1590 1591 #ifdef USE_ALLOCA 1592 alloca(p->AllocaSize); 1593 #endif 1594 1595 p->Res = CrcBig(p->Data, p->Size, p->NumIterations, 1596 p->CheckSumDefined ? &p->CheckSum : NULL, p->Hasher, 1597 p->Callback); 1598 return 0; 1599 } 1600 1601 struct CCrcThreads 1602 { 1603 CCrcInfo *Items; 1604 UInt32 NumThreads; 1605 1606 CCrcThreads(): Items(0), NumThreads(0) {} 1607 void WaitAll() 1608 { 1609 for (UInt32 i = 0; i < NumThreads; i++) 1610 Items[i].Wait(); 1611 NumThreads = 0; 1612 } 1613 ~CCrcThreads() 1614 { 1615 WaitAll(); 1616 delete []Items; 1617 } 1618 }; 1619 1620 #endif 1621 1622 static UInt32 CrcCalc1(const Byte *buf, UInt32 size) 1623 { 1624 UInt32 crc = CRC_INIT_VAL;; 1625 for (UInt32 i = 0; i < size; i++) 1626 crc = CRC_UPDATE_BYTE(crc, buf[i]); 1627 return CRC_GET_DIGEST(crc); 1628 } 1629 1630 static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG) 1631 { 1632 for (UInt32 i = 0; i < size; i++) 1633 buf[i] = (Byte)RG.GetRnd(); 1634 } 1635 1636 static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG) 1637 { 1638 RandGen(buf, size, RG); 1639 return CrcCalc1(buf, size); 1640 } 1641 1642 bool CrcInternalTest() 1643 { 1644 CBenchBuffer buffer; 1645 const UInt32 kBufferSize0 = (1 << 8); 1646 const UInt32 kBufferSize1 = (1 << 10); 1647 const UInt32 kCheckSize = (1 << 5); 1648 if (!buffer.Alloc(kBufferSize0 + kBufferSize1)) 1649 return false; 1650 Byte *buf = buffer.Buffer; 1651 UInt32 i; 1652 for (i = 0; i < kBufferSize0; i++) 1653 buf[i] = (Byte)i; 1654 UInt32 crc1 = CrcCalc1(buf, kBufferSize0); 1655 if (crc1 != 0x29058C73) 1656 return false; 1657 CBaseRandomGenerator RG; 1658 RandGen(buf + kBufferSize0, kBufferSize1, RG); 1659 for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++) 1660 for (UInt32 j = 0; j < kCheckSize; j++) 1661 if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j)) 1662 return false; 1663 return true; 1664 } 1665 1666 struct CBenchMethod 1667 { 1668 unsigned Weight; 1669 unsigned DictBits; 1670 UInt32 EncComplex; 1671 UInt32 DecComplexCompr; 1672 UInt32 DecComplexUnc; 1673 const char *Name; 1674 }; 1675 1676 static const CBenchMethod g_Bench[] = 1677 { 1678 { 40, 17, 357, 145, 20, "LZMA:x1" }, 1679 { 80, 24, 1220, 145, 20, "LZMA:x5:mt1" }, 1680 { 80, 24, 1220, 145, 20, "LZMA:x5:mt2" }, 1681 1682 { 10, 16, 124, 40, 14, "Deflate:x1" }, 1683 { 20, 16, 376, 40, 14, "Deflate:x5" }, 1684 { 10, 16, 1082, 40, 14, "Deflate:x7" }, 1685 { 10, 17, 422, 40, 14, "Deflate64:x5" }, 1686 1687 { 10, 15, 590, 69, 69, "BZip2:x1" }, 1688 { 20, 19, 815, 122, 122, "BZip2:x5" }, 1689 { 10, 19, 815, 122, 122, "BZip2:x5:mt2" }, 1690 { 10, 19, 2530, 122, 122, "BZip2:x7" }, 1691 1692 { 10, 18, 1010, 0, 1150, "PPMD:x1" }, 1693 { 10, 22, 1655, 0, 1830, "PPMD:x5" }, 1694 1695 { 2, 0, 6, 0, 6, "Delta:4" }, 1696 { 2, 0, 4, 0, 4, "BCJ" }, 1697 1698 { 10, 0, 24, 0, 24, "AES256CBC:1" }, 1699 { 2, 0, 8, 0, 2, "AES256CBC:2" } 1700 }; 1701 1702 struct CBenchHash 1703 { 1704 unsigned Weight; 1705 UInt32 Complex; 1706 UInt32 CheckSum; 1707 const char *Name; 1708 }; 1709 1710 static const CBenchHash g_Hash[] = 1711 { 1712 { 1, 1820, 0x8F8FEDAB, "CRC32:1" }, 1713 { 10, 558, 0x8F8FEDAB, "CRC32:4" }, 1714 { 10, 339, 0x8F8FEDAB, "CRC32:8" }, 1715 { 10, 512, 0xDF1C17CC, "CRC64" }, 1716 { 10, 5100, 0x2D79FF2E, "SHA256" }, 1717 { 10, 2340, 0x4C25132B, "SHA1" }, 1718 { 2, 5500, 0xE084E913, "BLAKE2sp" } 1719 }; 1720 1721 struct CTotalBenchRes 1722 { 1723 // UInt64 NumIterations1; // for Usage 1724 UInt64 NumIterations2; // for Rating / RPU 1725 1726 UInt64 Rating; 1727 UInt64 Usage; 1728 UInt64 RPU; 1729 1730 void Init() { /* NumIterations1 = 0; */ NumIterations2 = 0; Rating = 0; Usage = 0; RPU = 0; } 1731 1732 void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2) 1733 { 1734 Rating = (r1.Rating + r2.Rating); 1735 Usage = (r1.Usage + r2.Usage); 1736 RPU = (r1.RPU + r2.RPU); 1737 // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1); 1738 NumIterations2 = (r1.NumIterations2 + r2.NumIterations2); 1739 } 1740 }; 1741 1742 static void PrintNumber(IBenchPrintCallback &f, UInt64 value, unsigned size) 1743 { 1744 char s[128]; 1745 unsigned startPos = (unsigned)sizeof(s) - 32; 1746 memset(s, ' ', startPos); 1747 ConvertUInt64ToString(value, s + startPos); 1748 // if (withSpace) 1749 { 1750 startPos--; 1751 size++; 1752 } 1753 unsigned len = (unsigned)strlen(s + startPos); 1754 if (size > len) 1755 { 1756 startPos -= (size - len); 1757 if (startPos < 0) 1758 startPos = 0; 1759 } 1760 f.Print(s + startPos); 1761 } 1762 1763 static const unsigned kFieldSize_Name = 12; 1764 static const unsigned kFieldSize_SmallName = 4; 1765 static const unsigned kFieldSize_Speed = 9; 1766 static const unsigned kFieldSize_Usage = 5; 1767 static const unsigned kFieldSize_RU = 6; 1768 static const unsigned kFieldSize_Rating = 6; 1769 static const unsigned kFieldSize_EU = 5; 1770 static const unsigned kFieldSize_Effec = 5; 1771 1772 static const unsigned kFieldSize_TotalSize = 4 + kFieldSize_Speed + kFieldSize_Usage + kFieldSize_RU + kFieldSize_Rating; 1773 static const unsigned kFieldSize_EUAndEffec = 2 + kFieldSize_EU + kFieldSize_Effec; 1774 1775 1776 static void PrintRating(IBenchPrintCallback &f, UInt64 rating, unsigned size) 1777 { 1778 PrintNumber(f, (rating + 500000) / 1000000, size); 1779 } 1780 1781 1782 static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, unsigned size) 1783 { 1784 PrintNumber(f, (val * 100 + divider / 2) / divider, size); 1785 } 1786 1787 static void PrintChars(IBenchPrintCallback &f, char c, unsigned size) 1788 { 1789 char s[256]; 1790 memset(s, (Byte)c, size); 1791 s[size] = 0; 1792 f.Print(s); 1793 } 1794 1795 static void PrintSpaces(IBenchPrintCallback &f, unsigned size) 1796 { 1797 PrintChars(f, ' ', size); 1798 } 1799 1800 static void PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt64 rating, bool showFreq, UInt64 cpuFreq) 1801 { 1802 PrintNumber(f, (usage + 5000) / 10000, kFieldSize_Usage); 1803 PrintRating(f, rpu, kFieldSize_RU); 1804 PrintRating(f, rating, kFieldSize_Rating); 1805 if (showFreq) 1806 { 1807 if (cpuFreq == 0) 1808 PrintSpaces(f, kFieldSize_EUAndEffec); 1809 else 1810 { 1811 UInt64 ddd = cpuFreq * usage / 100; 1812 if (ddd == 0) 1813 ddd = 1; 1814 PrintPercents(f, (rating * 10000), ddd, kFieldSize_EU); 1815 PrintPercents(f, rating, cpuFreq, kFieldSize_Effec); 1816 } 1817 } 1818 } 1819 1820 static void PrintResults(IBenchPrintCallback *f, 1821 const CBenchInfo &info, 1822 unsigned weight, 1823 UInt64 rating, 1824 bool showFreq, UInt64 cpuFreq, 1825 CTotalBenchRes *res) 1826 { 1827 UInt64 speed = info.GetSpeed(info.UnpackSize * info.NumIterations); 1828 if (f) 1829 { 1830 if (speed != 0) 1831 PrintNumber(*f, speed / 1024, kFieldSize_Speed); 1832 else 1833 PrintSpaces(*f, 1 + kFieldSize_Speed); 1834 } 1835 UInt64 usage = info.GetUsage(); 1836 UInt64 rpu = info.GetRatingPerUsage(rating); 1837 if (f) 1838 { 1839 PrintResults(*f, usage, rpu, rating, showFreq, cpuFreq); 1840 } 1841 1842 if (res) 1843 { 1844 // res->NumIterations1++; 1845 res->NumIterations2 += weight; 1846 res->RPU += (rpu * weight); 1847 res->Rating += (rating * weight); 1848 res->Usage += (usage * weight); 1849 } 1850 } 1851 1852 static void PrintTotals(IBenchPrintCallback &f, bool showFreq, UInt64 cpuFreq, const CTotalBenchRes &res) 1853 { 1854 PrintSpaces(f, 1 + kFieldSize_Speed); 1855 // UInt64 numIterations1 = res.NumIterations1; if (numIterations1 == 0) numIterations1 = 1; 1856 UInt64 numIterations2 = res.NumIterations2; if (numIterations2 == 0) numIterations2 = 1; 1857 PrintResults(f, res.Usage / numIterations2, res.RPU / numIterations2, res.Rating / numIterations2, showFreq, cpuFreq); 1858 } 1859 1860 1861 static void PrintHex(AString &s, UInt64 v) 1862 { 1863 char temp[32]; 1864 ConvertUInt64ToHex(v, temp); 1865 s += temp; 1866 } 1867 1868 AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti) 1869 { 1870 AString s; 1871 // s.Add_UInt32(ti.numProcessThreads); 1872 if (ti.processAffinityMask != ti.systemAffinityMask) 1873 { 1874 // if (ti.numProcessThreads != ti.numSysThreads) 1875 { 1876 s += " / "; 1877 s.Add_UInt32(ti.GetNumSystemThreads()); 1878 } 1879 s += " : "; 1880 PrintHex(s, ti.processAffinityMask); 1881 s += " / "; 1882 PrintHex(s, ti.systemAffinityMask); 1883 } 1884 return s; 1885 } 1886 1887 1888 extern bool g_LargePagesMode; 1889 1890 1891 static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString, 1892 bool size_Defined, UInt64 size, const char *threadsString, UInt32 numThreads) 1893 { 1894 f.Print("RAM "); 1895 f.Print(sizeString); 1896 if (size_Defined) 1897 PrintNumber(f, (size >> 20), 6); 1898 else 1899 f.Print(" ?"); 1900 f.Print(" MB"); 1901 if (g_LargePagesMode) 1902 f.Print(" LP"); 1903 f.Print(", # "); 1904 f.Print(threadsString); 1905 PrintNumber(f, numThreads, 3); 1906 } 1907 1908 1909 1910 struct CBenchCallbackToPrint: public IBenchCallback 1911 { 1912 CBenchProps BenchProps; 1913 CTotalBenchRes EncodeRes; 1914 CTotalBenchRes DecodeRes; 1915 IBenchPrintCallback *_file; 1916 UInt32 DictSize; 1917 1918 bool Use2Columns; 1919 unsigned NameFieldSize; 1920 1921 bool ShowFreq; 1922 UInt64 CpuFreq; 1923 1924 unsigned EncodeWeight; 1925 unsigned DecodeWeight; 1926 1927 CBenchCallbackToPrint(): 1928 Use2Columns(false), 1929 NameFieldSize(0), 1930 ShowFreq(false), 1931 CpuFreq(0), 1932 EncodeWeight(1), 1933 DecodeWeight(1) 1934 {} 1935 1936 void Init() { EncodeRes.Init(); DecodeRes.Init(); } 1937 void Print(const char *s); 1938 void NewLine(); 1939 1940 HRESULT SetFreq(bool showFreq, UInt64 cpuFreq); 1941 HRESULT SetEncodeResult(const CBenchInfo &info, bool final); 1942 HRESULT SetDecodeResult(const CBenchInfo &info, bool final); 1943 }; 1944 1945 HRESULT CBenchCallbackToPrint::SetFreq(bool showFreq, UInt64 cpuFreq) 1946 { 1947 ShowFreq = showFreq; 1948 CpuFreq = cpuFreq; 1949 return S_OK; 1950 } 1951 1952 HRESULT CBenchCallbackToPrint::SetEncodeResult(const CBenchInfo &info, bool final) 1953 { 1954 RINOK(_file->CheckBreak()); 1955 if (final) 1956 { 1957 UInt64 rating = BenchProps.GetCompressRating(DictSize, info.GlobalTime, info.GlobalFreq, info.UnpackSize * info.NumIterations); 1958 PrintResults(_file, info, 1959 EncodeWeight, rating, 1960 ShowFreq, CpuFreq, &EncodeRes); 1961 if (!Use2Columns) 1962 _file->NewLine(); 1963 } 1964 return S_OK; 1965 } 1966 1967 static const char * const kSep = " | "; 1968 1969 HRESULT CBenchCallbackToPrint::SetDecodeResult(const CBenchInfo &info, bool final) 1970 { 1971 RINOK(_file->CheckBreak()); 1972 if (final) 1973 { 1974 UInt64 rating = BenchProps.GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations); 1975 if (Use2Columns) 1976 _file->Print(kSep); 1977 else 1978 PrintSpaces(*_file, NameFieldSize); 1979 CBenchInfo info2 = info; 1980 info2.UnpackSize *= info2.NumIterations; 1981 info2.PackSize *= info2.NumIterations; 1982 info2.NumIterations = 1; 1983 PrintResults(_file, info2, 1984 DecodeWeight, rating, 1985 ShowFreq, CpuFreq, &DecodeRes); 1986 } 1987 return S_OK; 1988 } 1989 1990 void CBenchCallbackToPrint::Print(const char *s) 1991 { 1992 _file->Print(s); 1993 } 1994 1995 void CBenchCallbackToPrint::NewLine() 1996 { 1997 _file->NewLine(); 1998 } 1999 2000 void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size) 2001 { 2002 f.Print(s); 2003 int numSpaces = size - MyStringLen(s); 2004 if (numSpaces > 0) 2005 PrintSpaces(f, numSpaces); 2006 } 2007 2008 void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size) 2009 { 2010 int numSpaces = size - MyStringLen(s); 2011 if (numSpaces > 0) 2012 PrintSpaces(f, numSpaces); 2013 f.Print(s); 2014 } 2015 2016 static HRESULT TotalBench( 2017 DECL_EXTERNAL_CODECS_LOC_VARS 2018 UInt64 complexInCommands, 2019 UInt32 numThreads, 2020 bool forceUnpackSize, 2021 size_t unpackSize, 2022 const Byte *fileData, 2023 IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback) 2024 { 2025 for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++) 2026 { 2027 const CBenchMethod &bench = g_Bench[i]; 2028 PrintLeft(*callback->_file, bench.Name, kFieldSize_Name); 2029 callback->BenchProps.DecComplexUnc = bench.DecComplexUnc; 2030 callback->BenchProps.DecComplexCompr = bench.DecComplexCompr; 2031 callback->BenchProps.EncComplex = bench.EncComplex; 2032 2033 COneMethodInfo method; 2034 NCOM::CPropVariant propVariant; 2035 propVariant = bench.Name; 2036 RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)); 2037 2038 size_t unpackSize2 = unpackSize; 2039 if (!forceUnpackSize && bench.DictBits == 0) 2040 unpackSize2 = kFilterUnpackSize; 2041 2042 callback->EncodeWeight = bench.Weight; 2043 callback->DecodeWeight = bench.Weight; 2044 2045 HRESULT res = MethodBench( 2046 EXTERNAL_CODECS_LOC_VARS 2047 complexInCommands, 2048 false, numThreads, method, 2049 unpackSize2, fileData, 2050 bench.DictBits, 2051 printCallback, callback, &callback->BenchProps); 2052 2053 if (res == E_NOTIMPL) 2054 { 2055 // callback->Print(" ---"); 2056 // we need additional empty line as line for decompression results 2057 if (!callback->Use2Columns) 2058 callback->NewLine(); 2059 } 2060 else 2061 { 2062 RINOK(res); 2063 } 2064 2065 callback->NewLine(); 2066 } 2067 return S_OK; 2068 } 2069 2070 2071 static HRESULT FreqBench( 2072 UInt64 complexInCommands, 2073 UInt32 numThreads, 2074 IBenchPrintCallback *_file, 2075 bool showFreq, 2076 UInt64 specifiedFreq, 2077 UInt64 &cpuFreq, 2078 UInt32 &res) 2079 { 2080 res = 0; 2081 cpuFreq = 0; 2082 2083 UInt32 bufferSize = 1 << 20; 2084 UInt32 complexity = kNumFreqCommands; 2085 if (numThreads == 0) 2086 numThreads = 1; 2087 2088 #ifdef _7ZIP_ST 2089 numThreads = 1; 2090 #endif 2091 2092 UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize); 2093 UInt64 numIterations = complexInCommands / complexity / bsize; 2094 if (numIterations == 0) 2095 numIterations = 1; 2096 2097 CBenchInfoCalc progressInfoSpec; 2098 2099 #ifndef _7ZIP_ST 2100 CFreqThreads threads; 2101 if (numThreads > 1) 2102 { 2103 threads.Items = new CFreqInfo[numThreads]; 2104 UInt32 i; 2105 for (i = 0; i < numThreads; i++) 2106 { 2107 CFreqInfo &info = threads.Items[i]; 2108 info.Callback = _file; 2109 info.CallbackRes = S_OK; 2110 info.NumIterations = numIterations; 2111 info.Size = bufferSize; 2112 } 2113 progressInfoSpec.SetStartTime(); 2114 for (i = 0; i < numThreads; i++) 2115 { 2116 CFreqInfo &info = threads.Items[i]; 2117 RINOK(info.Thread.Create(FreqThreadFunction, &info)); 2118 threads.NumThreads++; 2119 } 2120 threads.WaitAll(); 2121 for (i = 0; i < numThreads; i++) 2122 { 2123 RINOK(threads.Items[i].CallbackRes); 2124 } 2125 } 2126 else 2127 #endif 2128 { 2129 progressInfoSpec.SetStartTime(); 2130 UInt32 sum = g_BenchCpuFreqTemp; 2131 for (UInt64 k = numIterations; k > 0; k--) 2132 { 2133 RINOK(_file->CheckBreak()); 2134 sum = CountCpuFreq(sum, bufferSize, g_BenchCpuFreqTemp); 2135 } 2136 res += sum; 2137 } 2138 2139 CBenchInfo info; 2140 progressInfoSpec.SetFinishTime(info); 2141 2142 info.UnpackSize = 0; 2143 info.PackSize = 0; 2144 info.NumIterations = 1; 2145 2146 if (_file) 2147 { 2148 { 2149 UInt64 numCommands = (UInt64)numIterations * bufferSize * numThreads * complexity; 2150 UInt64 rating = info.GetSpeed(numCommands); 2151 cpuFreq = rating / numThreads; 2152 PrintResults(_file, info, 2153 0, // weight 2154 rating, 2155 showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : cpuFreq) : 0, NULL); 2156 } 2157 RINOK(_file->CheckBreak()); 2158 } 2159 2160 return S_OK; 2161 } 2162 2163 2164 2165 static HRESULT CrcBench( 2166 DECL_EXTERNAL_CODECS_LOC_VARS 2167 UInt64 complexInCommands, 2168 UInt32 numThreads, UInt32 bufferSize, 2169 UInt64 &speed, 2170 UInt32 complexity, unsigned benchWeight, 2171 const UInt32 *checkSum, 2172 const COneMethodInfo &method, 2173 IBenchPrintCallback *_file, 2174 CTotalBenchRes *encodeRes, 2175 bool showFreq, UInt64 cpuFreq) 2176 { 2177 if (numThreads == 0) 2178 numThreads = 1; 2179 2180 #ifdef _7ZIP_ST 2181 numThreads = 1; 2182 #endif 2183 2184 const AString &methodName = method.MethodName; 2185 // methodName.RemoveChar(L'-'); 2186 CMethodId hashID; 2187 if (!FindHashMethod( 2188 EXTERNAL_CODECS_LOC_VARS 2189 methodName, hashID)) 2190 return E_NOTIMPL; 2191 2192 CBenchBuffer buffer; 2193 size_t totalSize = (size_t)bufferSize * numThreads; 2194 if (totalSize / numThreads != bufferSize) 2195 return E_OUTOFMEMORY; 2196 if (!buffer.Alloc(totalSize)) 2197 return E_OUTOFMEMORY; 2198 2199 Byte *buf = buffer.Buffer; 2200 CBaseRandomGenerator RG; 2201 UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize); 2202 UInt64 numIterations = complexInCommands * 256 / complexity / bsize; 2203 if (numIterations == 0) 2204 numIterations = 1; 2205 2206 CBenchInfoCalc progressInfoSpec; 2207 2208 #ifndef _7ZIP_ST 2209 CCrcThreads threads; 2210 if (numThreads > 1) 2211 { 2212 threads.Items = new CCrcInfo[numThreads]; 2213 2214 UInt32 i; 2215 for (i = 0; i < numThreads; i++) 2216 { 2217 CCrcInfo &info = threads.Items[i]; 2218 AString name; 2219 RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, info.Hasher)); 2220 if (!info.Hasher) 2221 return E_NOTIMPL; 2222 CMyComPtr<ICompressSetCoderProperties> scp; 2223 info.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); 2224 if (scp) 2225 { 2226 UInt64 reduceSize = 1; 2227 RINOK(method.SetCoderProps(scp, &reduceSize)); 2228 } 2229 2230 Byte *data = buf + (size_t)bufferSize * i; 2231 info.Callback = _file; 2232 info.Data = data; 2233 info.NumIterations = numIterations; 2234 info.Size = bufferSize; 2235 /* info.Crc = */ RandGenCrc(data, bufferSize, RG); 2236 info.CheckSumDefined = false; 2237 if (checkSum) 2238 { 2239 info.CheckSum = *checkSum; 2240 info.CheckSumDefined = (checkSum && (i == 0)); 2241 } 2242 2243 #ifdef USE_ALLOCA 2244 info.AllocaSize = (i * 16 * 21) & 0x7FF; 2245 #endif 2246 } 2247 2248 progressInfoSpec.SetStartTime(); 2249 2250 for (i = 0; i < numThreads; i++) 2251 { 2252 CCrcInfo &info = threads.Items[i]; 2253 RINOK(info.Thread.Create(CrcThreadFunction, &info)); 2254 threads.NumThreads++; 2255 } 2256 threads.WaitAll(); 2257 for (i = 0; i < numThreads; i++) 2258 { 2259 RINOK(threads.Items[i].Res); 2260 } 2261 } 2262 else 2263 #endif 2264 { 2265 /* UInt32 crc = */ RandGenCrc(buf, bufferSize, RG); 2266 progressInfoSpec.SetStartTime(); 2267 CMyComPtr<IHasher> hasher; 2268 AString name; 2269 RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher)); 2270 if (!hasher) 2271 return E_NOTIMPL; 2272 CMyComPtr<ICompressSetCoderProperties> scp; 2273 hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); 2274 if (scp) 2275 { 2276 UInt64 reduceSize = 1; 2277 RINOK(method.SetCoderProps(scp, &reduceSize)); 2278 } 2279 RINOK(CrcBig(buf, bufferSize, numIterations, checkSum, hasher, _file)); 2280 } 2281 2282 CBenchInfo info; 2283 progressInfoSpec.SetFinishTime(info); 2284 2285 UInt64 unpSize = numIterations * bufferSize; 2286 UInt64 unpSizeThreads = unpSize * numThreads; 2287 info.UnpackSize = unpSizeThreads; 2288 info.PackSize = unpSizeThreads; 2289 info.NumIterations = 1; 2290 2291 if (_file) 2292 { 2293 { 2294 UInt64 numCommands = unpSizeThreads * complexity / 256; 2295 UInt64 rating = info.GetSpeed(numCommands); 2296 PrintResults(_file, info, 2297 benchWeight, rating, 2298 showFreq, cpuFreq, encodeRes); 2299 } 2300 RINOK(_file->CheckBreak()); 2301 } 2302 2303 speed = info.GetSpeed(unpSizeThreads); 2304 2305 return S_OK; 2306 } 2307 2308 static HRESULT TotalBench_Hash( 2309 DECL_EXTERNAL_CODECS_LOC_VARS 2310 UInt64 complexInCommands, 2311 UInt32 numThreads, UInt32 bufSize, 2312 IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback, 2313 CTotalBenchRes *encodeRes, 2314 bool showFreq, UInt64 cpuFreq) 2315 { 2316 for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++) 2317 { 2318 const CBenchHash &bench = g_Hash[i]; 2319 PrintLeft(*callback->_file, bench.Name, kFieldSize_Name); 2320 // callback->BenchProps.DecComplexUnc = bench.DecComplexUnc; 2321 // callback->BenchProps.DecComplexCompr = bench.DecComplexCompr; 2322 // callback->BenchProps.EncComplex = bench.EncComplex; 2323 2324 COneMethodInfo method; 2325 NCOM::CPropVariant propVariant; 2326 propVariant = bench.Name; 2327 RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)); 2328 2329 UInt64 speed; 2330 HRESULT res = CrcBench( 2331 EXTERNAL_CODECS_LOC_VARS 2332 complexInCommands, 2333 numThreads, bufSize, 2334 speed, 2335 bench.Complex, bench.Weight, 2336 &bench.CheckSum, method, 2337 printCallback, encodeRes, showFreq, cpuFreq); 2338 if (res == E_NOTIMPL) 2339 { 2340 // callback->Print(" ---"); 2341 } 2342 else 2343 { 2344 RINOK(res); 2345 } 2346 callback->NewLine(); 2347 } 2348 return S_OK; 2349 } 2350 2351 struct CTempValues 2352 { 2353 UInt64 *Values; 2354 CTempValues(UInt32 num) { Values = new UInt64[num]; } 2355 ~CTempValues() { delete []Values; } 2356 }; 2357 2358 static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) 2359 { 2360 const wchar_t *end; 2361 UInt64 result = ConvertStringToUInt64(s, &end); 2362 if (*end != 0 || s.IsEmpty()) 2363 prop = s; 2364 else if (result <= (UInt32)0xFFFFFFFF) 2365 prop = (UInt32)result; 2366 else 2367 prop = result; 2368 } 2369 2370 static UInt32 GetNumThreadsNext(unsigned i, UInt32 numThreads) 2371 { 2372 if (i < 2) 2373 return i + 1; 2374 i -= 1; 2375 UInt32 num = (UInt32)(2 + (i & 1)) << (i >> 1); 2376 return (num <= numThreads) ? num : numThreads; 2377 } 2378 2379 static bool AreSameMethodNames(const char *fullName, const char *shortName) 2380 { 2381 return StringsAreEqualNoCase_Ascii(fullName, shortName); 2382 } 2383 2384 2385 #ifdef MY_CPU_X86_OR_AMD64 2386 2387 static void PrintCpuChars(AString &s, UInt32 v) 2388 { 2389 for (int j = 0; j < 4; j++) 2390 { 2391 Byte b = (Byte)(v & 0xFF); 2392 v >>= 8; 2393 if (b == 0) 2394 break; 2395 s += (char)b; 2396 } 2397 } 2398 2399 static void x86cpuid_to_String(const Cx86cpuid &c, AString &s) 2400 { 2401 s.Empty(); 2402 2403 UInt32 maxFunc2 = 0; 2404 UInt32 t[3]; 2405 2406 MyCPUID(0x80000000, &maxFunc2, &t[0], &t[1], &t[2]); 2407 2408 bool fullNameIsAvail = (maxFunc2 >= 0x80000004); 2409 2410 if (!fullNameIsAvail) 2411 { 2412 for (int i = 0; i < 3; i++) 2413 PrintCpuChars(s, c.vendor[i]); 2414 } 2415 else 2416 { 2417 for (int i = 0; i < 3; i++) 2418 { 2419 UInt32 d[4] = { 0 }; 2420 MyCPUID(0x80000002 + i, &d[0], &d[1], &d[2], &d[3]); 2421 for (int j = 0; j < 4; j++) 2422 PrintCpuChars(s, d[j]); 2423 } 2424 } 2425 2426 s.Add_Space_if_NotEmpty(); 2427 { 2428 char temp[32]; 2429 ConvertUInt32ToHex(c.ver, temp); 2430 s += '('; 2431 s += temp; 2432 s += ')'; 2433 } 2434 } 2435 2436 #endif 2437 2438 2439 2440 static const char * const k_PROCESSOR_ARCHITECTURE[] = 2441 { 2442 "x86" // "INTEL" 2443 , "MIPS" 2444 , "ALPHA" 2445 , "PPC" 2446 , "SHX" 2447 , "ARM" 2448 , "IA64" 2449 , "ALPHA64" 2450 , "MSIL" 2451 , "x64" // "AMD64" 2452 , "IA32_ON_WIN64" 2453 , "NEUTRAL" 2454 , "ARM64" 2455 , "ARM32_ON_WIN64" 2456 }; 2457 2458 #define MY__PROCESSOR_ARCHITECTURE_INTEL 0 2459 #define MY__PROCESSOR_ARCHITECTURE_AMD64 9 2460 2461 2462 #define MY__PROCESSOR_INTEL_PENTIUM 586 2463 #define MY__PROCESSOR_AMD_X8664 8664 2464 2465 /* 2466 static const CUInt32PCharPair k_PROCESSOR[] = 2467 { 2468 { 2200, "IA64" }, 2469 { 8664, "x64" } 2470 }; 2471 2472 #define PROCESSOR_INTEL_386 386 2473 #define PROCESSOR_INTEL_486 486 2474 #define PROCESSOR_INTEL_PENTIUM 586 2475 #define PROCESSOR_INTEL_860 860 2476 #define PROCESSOR_INTEL_IA64 2200 2477 #define PROCESSOR_AMD_X8664 8664 2478 #define PROCESSOR_MIPS_R2000 2000 2479 #define PROCESSOR_MIPS_R3000 3000 2480 #define PROCESSOR_MIPS_R4000 4000 2481 #define PROCESSOR_ALPHA_21064 21064 2482 #define PROCESSOR_PPC_601 601 2483 #define PROCESSOR_PPC_603 603 2484 #define PROCESSOR_PPC_604 604 2485 #define PROCESSOR_PPC_620 620 2486 #define PROCESSOR_HITACHI_SH3 10003 2487 #define PROCESSOR_HITACHI_SH3E 10004 2488 #define PROCESSOR_HITACHI_SH4 10005 2489 #define PROCESSOR_MOTOROLA_821 821 2490 #define PROCESSOR_SHx_SH3 103 2491 #define PROCESSOR_SHx_SH4 104 2492 #define PROCESSOR_STRONGARM 2577 // 0xA11 2493 #define PROCESSOR_ARM720 1824 // 0x720 2494 #define PROCESSOR_ARM820 2080 // 0x820 2495 #define PROCESSOR_ARM920 2336 // 0x920 2496 #define PROCESSOR_ARM_7TDMI 70001 2497 #define PROCESSOR_OPTIL 18767 // 0x494f 2498 */ 2499 2500 #ifdef _WIN32 2501 2502 static const char * const k_PF[] = 2503 { 2504 "FP_ERRATA" 2505 , "FP_EMU" 2506 , "CMPXCHG" 2507 , "MMX" 2508 , "PPC_MOVEMEM_64BIT" 2509 , "ALPHA_BYTE" 2510 , "SSE" 2511 , "3DNOW" 2512 , "RDTSC" 2513 , "PAE" 2514 , "SSE2" 2515 , "SSE_DAZ" 2516 , "NX" 2517 , "SSE3" 2518 , "CMPXCHG16B" 2519 , "CMP8XCHG16" 2520 , "CHANNELS" 2521 , "XSAVE" 2522 , "ARM_VFP_32" 2523 , "ARM_NEON" 2524 , "L2AT" 2525 , "VIRT_FIRMWARE" 2526 , "RDWRFSGSBASE" 2527 , "FASTFAIL" 2528 , "ARM_DIVIDE" 2529 , "ARM_64BIT_LOADSTORE_ATOMIC" 2530 , "ARM_EXTERNAL_CACHE" 2531 , "ARM_FMAC" 2532 , "RDRAND" 2533 , "ARM_V8" 2534 , "ARM_V8_CRYPTO" 2535 , "ARM_V8_CRC32" 2536 , "RDTSCP" 2537 }; 2538 2539 #endif 2540 2541 2542 static void PrintSize(AString &s, UInt64 v) 2543 { 2544 char c = 0; 2545 if ((v & 0x3FF) == 0) { v >>= 10; c = 'K'; 2546 if ((v & 0x3FF) == 0) { v >>= 10; c = 'M'; 2547 if ((v & 0x3FF) == 0) { v >>= 10; c = 'G'; 2548 if ((v & 0x3FF) == 0) { v >>= 10; c = 'T'; 2549 }}}} 2550 else 2551 { 2552 PrintHex(s, v); 2553 return; 2554 } 2555 char temp[32]; 2556 ConvertUInt64ToString(v, temp); 2557 s += temp; 2558 if (c) 2559 s += c; 2560 } 2561 2562 2563 static void PrintPage(AString &s, UInt32 v) 2564 { 2565 if ((v & 0x3FF) == 0) 2566 { 2567 s.Add_UInt32(v >> 10); 2568 s += "K"; 2569 } 2570 else 2571 s.Add_UInt32(v >> 10); 2572 } 2573 2574 static AString TypeToString2(const char * const table[], unsigned num, UInt32 value) 2575 { 2576 char sz[16]; 2577 const char *p = NULL; 2578 if (value < num) 2579 p = table[value]; 2580 if (!p) 2581 { 2582 ConvertUInt32ToString(value, sz); 2583 p = sz; 2584 } 2585 return (AString)p; 2586 } 2587 2588 #ifdef _WIN32 2589 2590 static void SysInfo_To_String(AString &s, const SYSTEM_INFO &si) 2591 { 2592 s += TypeToString2(k_PROCESSOR_ARCHITECTURE, ARRAY_SIZE(k_PROCESSOR_ARCHITECTURE), si.wProcessorArchitecture); 2593 2594 if (!( si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_INTEL && si.dwProcessorType == MY__PROCESSOR_INTEL_PENTIUM 2595 || si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_AMD64 && si.dwProcessorType == MY__PROCESSOR_AMD_X8664)) 2596 { 2597 s += " "; 2598 // s += TypePairToString(k_PROCESSOR, ARRAY_SIZE(k_PROCESSOR), si.dwProcessorType); 2599 s.Add_UInt32(si.dwProcessorType); 2600 } 2601 s += " "; 2602 PrintHex(s, si.wProcessorLevel); 2603 s += "."; 2604 PrintHex(s, si.wProcessorRevision); 2605 if ((UInt64)si.dwActiveProcessorMask + 1 != ((UInt64)1 << si.dwNumberOfProcessors)) 2606 if ((UInt64)si.dwActiveProcessorMask + 1 != 0 || si.dwNumberOfProcessors != sizeof(UInt64) * 8) 2607 { 2608 s += " act:"; 2609 PrintHex(s, si.dwActiveProcessorMask); 2610 } 2611 s += " cpus:"; 2612 s.Add_UInt32(si.dwNumberOfProcessors); 2613 if (si.dwPageSize != 1 << 12) 2614 { 2615 s += " page:"; 2616 PrintPage(s, si.dwPageSize); 2617 } 2618 if (si.dwAllocationGranularity != 1 << 16) 2619 { 2620 s += " gran:"; 2621 PrintPage(s, si.dwAllocationGranularity); 2622 } 2623 s += " "; 2624 2625 DWORD_PTR minAdd = (DWORD_PTR)si.lpMinimumApplicationAddress; 2626 UInt64 maxSize = (UInt64)(DWORD_PTR)si.lpMaximumApplicationAddress + 1; 2627 const UInt32 kReserveSize = ((UInt32)1 << 16); 2628 if (minAdd != kReserveSize) 2629 { 2630 PrintSize(s, minAdd); 2631 s += "-"; 2632 } 2633 else 2634 { 2635 if ((maxSize & (kReserveSize - 1)) == 0) 2636 maxSize += kReserveSize; 2637 } 2638 PrintSize(s, maxSize); 2639 } 2640 2641 #ifndef _WIN64 2642 typedef VOID (WINAPI *Func_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo); 2643 #endif 2644 2645 #endif 2646 2647 void GetSysInfo(AString &s1, AString &s2) 2648 { 2649 s1.Empty(); 2650 s2.Empty(); 2651 2652 #ifdef _WIN32 2653 SYSTEM_INFO si; 2654 GetSystemInfo(&si); 2655 { 2656 SysInfo_To_String(s1, si); 2657 // s += " : "; 2658 } 2659 2660 #if !defined(_WIN64) && !defined(UNDER_CE) 2661 Func_GetNativeSystemInfo fn_GetNativeSystemInfo = (Func_GetNativeSystemInfo)GetProcAddress( 2662 GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"); 2663 if (fn_GetNativeSystemInfo) 2664 { 2665 SYSTEM_INFO si2; 2666 fn_GetNativeSystemInfo(&si2); 2667 // if (memcmp(&si, &si2, sizeof(si)) != 0) 2668 { 2669 // s += " - "; 2670 SysInfo_To_String(s2, si2); 2671 } 2672 } 2673 #endif 2674 #endif 2675 } 2676 2677 2678 void GetCpuName(AString &s) 2679 { 2680 s.Empty(); 2681 2682 #ifdef MY_CPU_X86_OR_AMD64 2683 { 2684 Cx86cpuid cpuid; 2685 if (x86cpuid_CheckAndRead(&cpuid)) 2686 { 2687 AString s2; 2688 x86cpuid_to_String(cpuid, s2); 2689 s += s2; 2690 } 2691 else 2692 { 2693 #ifdef MY_CPU_AMD64 2694 s += "x64"; 2695 #else 2696 s += "x86"; 2697 #endif 2698 } 2699 } 2700 #else 2701 2702 #ifdef MY_CPU_LE 2703 s += "LE"; 2704 #elif defined(MY_CPU_BE) 2705 s += "BE"; 2706 #endif 2707 2708 #endif 2709 2710 if (g_LargePagesMode) 2711 s += " (LP)"; 2712 } 2713 2714 2715 void GetCpuFeatures(AString &s) 2716 { 2717 s.Empty(); 2718 2719 #ifdef _WIN32 2720 const unsigned kNumFeatures_Extra = 32; // we check also for unknown features 2721 const unsigned kNumFeatures = ARRAY_SIZE(k_PF) + kNumFeatures_Extra; 2722 for (unsigned i = 0; i < kNumFeatures; i++) 2723 { 2724 if (IsProcessorFeaturePresent(i)) 2725 { 2726 s.Add_Space_if_NotEmpty(); 2727 s += TypeToString2(k_PF, ARRAY_SIZE(k_PF), i); 2728 } 2729 } 2730 #endif 2731 } 2732 2733 2734 #ifdef _WIN32 2735 #ifndef UNDER_CE 2736 2737 typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *); 2738 2739 static BOOL My_RtlGetVersion(OSVERSIONINFOEXW *vi) 2740 { 2741 HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); 2742 if (!ntdll) 2743 return FALSE; 2744 Func_RtlGetVersion func = (Func_RtlGetVersion)GetProcAddress(ntdll, "RtlGetVersion"); 2745 if (!func) 2746 return FALSE; 2747 func(vi); 2748 return TRUE; 2749 } 2750 2751 #endif 2752 #endif 2753 2754 2755 HRESULT Bench( 2756 DECL_EXTERNAL_CODECS_LOC_VARS 2757 IBenchPrintCallback *printCallback, 2758 IBenchCallback *benchCallback, 2759 // IBenchFreqCallback *freqCallback, 2760 const CObjectVector<CProperty> &props, 2761 UInt32 numIterations, 2762 bool multiDict) 2763 { 2764 if (!CrcInternalTest()) 2765 return S_FALSE; 2766 2767 UInt32 numCPUs = 1; 2768 UInt64 ramSize = (UInt64)(sizeof(size_t)) << 29; 2769 2770 NSystem::CProcessAffinity threadsInfo; 2771 threadsInfo.InitST(); 2772 2773 #ifndef _7ZIP_ST 2774 2775 if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0) 2776 numCPUs = threadsInfo.GetNumProcessThreads(); 2777 else 2778 numCPUs = NSystem::GetNumberOfProcessors(); 2779 2780 #endif 2781 2782 bool ramSize_Defined = NSystem::GetRamSize(ramSize); 2783 2784 UInt32 numThreadsSpecified = numCPUs; 2785 2786 UInt32 testTime = kComplexInSeconds; 2787 2788 UInt64 specifiedFreq = 0; 2789 2790 bool multiThreadTests = false; 2791 2792 COneMethodInfo method; 2793 2794 CBenchBuffer fileDataBuffer; 2795 2796 { 2797 unsigned i; 2798 for (i = 0; i < props.Size(); i++) 2799 { 2800 const CProperty &property = props[i]; 2801 UString name (property.Name); 2802 name.MakeLower_Ascii(); 2803 2804 if (name.IsEqualTo("file")) 2805 { 2806 if (property.Value.IsEmpty()) 2807 return E_INVALIDARG; 2808 2809 #ifdef USE_WIN_FILE 2810 2811 NFile::NIO::CInFile file; 2812 if (!file.Open(us2fs(property.Value))) 2813 return E_INVALIDARG; 2814 UInt64 len; 2815 if (!file.GetLength(len)) 2816 return E_FAIL; 2817 if (len >= ((UInt32)1 << 31) || len == 0) 2818 return E_INVALIDARG; 2819 if (!fileDataBuffer.Alloc((size_t)len)) 2820 return E_OUTOFMEMORY; 2821 UInt32 processedSize; 2822 file.Read(fileDataBuffer.Buffer, (UInt32)len, processedSize); 2823 if (processedSize != len) 2824 return E_FAIL; 2825 if (printCallback) 2826 { 2827 printCallback->Print("file size ="); 2828 PrintNumber(*printCallback, len, 0); 2829 printCallback->NewLine(); 2830 } 2831 continue; 2832 2833 #else 2834 2835 return E_NOTIMPL; 2836 2837 #endif 2838 } 2839 2840 NCOM::CPropVariant propVariant; 2841 if (!property.Value.IsEmpty()) 2842 ParseNumberString(property.Value, propVariant); 2843 2844 if (name.IsEqualTo("time")) 2845 { 2846 RINOK(ParsePropToUInt32(UString(), propVariant, testTime)); 2847 continue; 2848 } 2849 2850 if (name.IsEqualTo("freq")) 2851 { 2852 UInt32 freq32 = 0; 2853 RINOK(ParsePropToUInt32(UString(), propVariant, freq32)); 2854 if (freq32 == 0) 2855 return E_INVALIDARG; 2856 specifiedFreq = (UInt64)freq32 * 1000000; 2857 2858 if (printCallback) 2859 { 2860 printCallback->Print("freq="); 2861 PrintNumber(*printCallback, freq32, 0); 2862 printCallback->NewLine(); 2863 } 2864 2865 continue; 2866 } 2867 2868 if (name.IsPrefixedBy_Ascii_NoCase("mt")) 2869 { 2870 UString s = name.Ptr(2); 2871 if (s.IsEqualTo("*") 2872 || s.IsEmpty() && propVariant.vt == VT_BSTR && StringsAreEqual_Ascii(propVariant.bstrVal, "*")) 2873 { 2874 multiThreadTests = true; 2875 continue; 2876 } 2877 #ifndef _7ZIP_ST 2878 RINOK(ParseMtProp(s, propVariant, numCPUs, numThreadsSpecified)); 2879 #endif 2880 continue; 2881 } 2882 2883 RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant)); 2884 } 2885 } 2886 2887 if (printCallback) 2888 { 2889 #ifdef _WIN32 2890 #ifndef UNDER_CE 2891 { 2892 AString s; 2893 // OSVERSIONINFO vi; 2894 OSVERSIONINFOEXW vi; 2895 vi.dwOSVersionInfoSize = sizeof(vi); 2896 // if (::GetVersionEx(&vi)) 2897 if (My_RtlGetVersion(&vi)) 2898 { 2899 s += "Windows"; 2900 if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) 2901 s.Add_UInt32(vi.dwPlatformId); 2902 s += " "; s.Add_UInt32(vi.dwMajorVersion); 2903 s += "."; s.Add_UInt32(vi.dwMinorVersion); 2904 s += " "; s.Add_UInt32(vi.dwBuildNumber); 2905 // s += " "; s += GetAnsiString(vi.szCSDVersion); 2906 } 2907 printCallback->Print(s); 2908 printCallback->NewLine(); 2909 } 2910 #endif 2911 #endif 2912 2913 { 2914 AString s1, s2; 2915 GetSysInfo(s1, s2); 2916 if (!s1.IsEmpty() || !s2.IsEmpty()) 2917 { 2918 printCallback->Print(s1); 2919 if (s1 != s2 && !s2.IsEmpty()) 2920 { 2921 printCallback->Print(" - "); 2922 printCallback->Print(s2); 2923 } 2924 printCallback->NewLine(); 2925 } 2926 } 2927 { 2928 AString s; 2929 GetCpuFeatures(s); 2930 if (!s.IsEmpty()) 2931 { 2932 printCallback->Print(s); 2933 printCallback->NewLine(); 2934 } 2935 } 2936 { 2937 AString s; 2938 GetCpuName(s); 2939 if (!s.IsEmpty()) 2940 { 2941 printCallback->Print(s); 2942 printCallback->NewLine(); 2943 } 2944 } 2945 } 2946 2947 if (printCallback) 2948 { 2949 printCallback->Print("CPU Freq:"); 2950 } 2951 2952 UInt64 complexInCommands = kComplexInCommands; 2953 2954 if (printCallback /* || freqCallback */) 2955 { 2956 UInt64 numMilCommands = 1 << 6; 2957 if (specifiedFreq != 0) 2958 { 2959 while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000)) 2960 numMilCommands >>= 1; 2961 } 2962 2963 for (int jj = 0;; jj++) 2964 { 2965 if (printCallback) 2966 RINOK(printCallback->CheckBreak()); 2967 2968 UInt64 start = ::GetTimeCount(); 2969 UInt32 sum = (UInt32)start; 2970 sum = CountCpuFreq(sum, (UInt32)(numMilCommands * 1000000 / kNumFreqCommands), g_BenchCpuFreqTemp); 2971 const UInt64 realDelta = ::GetTimeCount() - start; 2972 start = realDelta; 2973 if (start == 0) 2974 start = 1; 2975 UInt64 freq = GetFreq(); 2976 // mips is constant in some compilers 2977 const UInt64 mipsVal = numMilCommands * freq / start; 2978 if (printCallback) 2979 { 2980 if (realDelta == 0) 2981 { 2982 printCallback->Print(" -"); 2983 } 2984 else 2985 { 2986 // PrintNumber(*printCallback, start, 0); 2987 PrintNumber(*printCallback, mipsVal, 5 + ((sum == 0xF1541213) ? 1 : 0)); 2988 } 2989 } 2990 /* 2991 if (freqCallback) 2992 freqCallback->AddCpuFreq(mipsVal); 2993 */ 2994 2995 if (jj >= 3) 2996 { 2997 SetComplexCommands(testTime, false, mipsVal * 1000000, complexInCommands); 2998 if (jj >= 8 || start >= freq) 2999 break; 3000 // break; // change it 3001 numMilCommands <<= 1; 3002 } 3003 } 3004 } 3005 3006 if (printCallback) 3007 { 3008 printCallback->NewLine(); 3009 printCallback->NewLine(); 3010 PrintRequirements(*printCallback, "size: ", ramSize_Defined, ramSize, "CPU hardware threads:", numCPUs); 3011 printCallback->Print(GetProcessThreadsInfo(threadsInfo)); 3012 printCallback->NewLine(); 3013 } 3014 3015 if (numThreadsSpecified < 1 || numThreadsSpecified > kNumThreadsMax) 3016 return E_INVALIDARG; 3017 3018 UInt32 dict; 3019 bool dictIsDefined = method.Get_DicSize(dict); 3020 3021 if (method.MethodName.IsEmpty()) 3022 method.MethodName = "LZMA"; 3023 3024 if (benchCallback) 3025 { 3026 CBenchProps benchProps; 3027 benchProps.SetLzmaCompexity(); 3028 UInt32 dictSize = method.Get_Lzma_DicSize(); 3029 UInt32 uncompressedDataSize = kAdditionalSize + dictSize; 3030 return MethodBench( 3031 EXTERNAL_CODECS_LOC_VARS 3032 complexInCommands, 3033 true, numThreadsSpecified, 3034 method, 3035 uncompressedDataSize, fileDataBuffer.Buffer, 3036 kOldLzmaDictBits, printCallback, benchCallback, &benchProps); 3037 } 3038 3039 AString methodName (method.MethodName); 3040 if (methodName.IsEqualTo_Ascii_NoCase("CRC")) 3041 methodName = "crc32"; 3042 method.MethodName = methodName; 3043 CMethodId hashID; 3044 3045 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID)) 3046 { 3047 if (!printCallback) 3048 return S_FALSE; 3049 IBenchPrintCallback &f = *printCallback; 3050 if (!dictIsDefined) 3051 dict = (1 << 24); 3052 3053 3054 // methhodName.RemoveChar(L'-'); 3055 UInt32 complexity = 10000; 3056 const UInt32 *checkSum = NULL; 3057 { 3058 unsigned i; 3059 for (i = 0; i < ARRAY_SIZE(g_Hash); i++) 3060 { 3061 const CBenchHash &h = g_Hash[i]; 3062 AString benchMethod (h.Name); 3063 AString benchProps; 3064 int propPos = benchMethod.Find(':'); 3065 if (propPos >= 0) 3066 { 3067 benchProps = benchMethod.Ptr(propPos + 1); 3068 benchMethod.DeleteFrom(propPos); 3069 } 3070 3071 if (AreSameMethodNames(benchMethod, methodName)) 3072 { 3073 if (benchProps.IsEmpty() 3074 || benchMethod.IsEqualTo_Ascii_NoCase("crc32") && benchProps == "8" && method.PropsString.IsEmpty() 3075 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps)) 3076 { 3077 complexity = h.Complex; 3078 checkSum = &h.CheckSum; 3079 if (method.PropsString.IsEqualTo_Ascii_NoCase(benchProps)) 3080 break; 3081 } 3082 } 3083 } 3084 if (i == ARRAY_SIZE(g_Hash)) 3085 return E_NOTIMPL; 3086 } 3087 3088 f.NewLine(); 3089 f.Print("Size"); 3090 const unsigned kFieldSize_CrcSpeed = 6; 3091 unsigned numThreadsTests = 0; 3092 for (;;) 3093 { 3094 UInt32 t = GetNumThreadsNext(numThreadsTests, numThreadsSpecified); 3095 PrintNumber(f, t, kFieldSize_CrcSpeed); 3096 numThreadsTests++; 3097 if (t >= numThreadsSpecified) 3098 break; 3099 } 3100 f.NewLine(); 3101 f.NewLine(); 3102 CTempValues speedTotals(numThreadsTests); 3103 { 3104 for (unsigned ti = 0; ti < numThreadsTests; ti++) 3105 speedTotals.Values[ti] = 0; 3106 } 3107 3108 UInt64 numSteps = 0; 3109 for (UInt32 i = 0; i < numIterations; i++) 3110 { 3111 for (unsigned pow = 10; pow < 32; pow++) 3112 { 3113 UInt32 bufSize = (UInt32)1 << pow; 3114 if (bufSize > dict) 3115 break; 3116 char s[16]; 3117 ConvertUInt32ToString(pow, s); 3118 unsigned pos = MyStringLen(s); 3119 s[pos++] = ':'; 3120 s[pos++] = ' '; 3121 s[pos] = 0; 3122 f.Print(s); 3123 3124 for (unsigned ti = 0; ti < numThreadsTests; ti++) 3125 { 3126 RINOK(f.CheckBreak()); 3127 UInt32 t = GetNumThreadsNext(ti, numThreadsSpecified); 3128 UInt64 speed = 0; 3129 RINOK(CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands, 3130 t, bufSize, speed, 3131 complexity, 3132 1, // benchWeight, 3133 (pow == kNumHashDictBits) ? checkSum : NULL, method, NULL, NULL, false, 0)); 3134 PrintNumber(f, (speed >> 20), kFieldSize_CrcSpeed); 3135 speedTotals.Values[ti] += speed; 3136 } 3137 f.NewLine(); 3138 numSteps++; 3139 } 3140 } 3141 if (numSteps != 0) 3142 { 3143 f.NewLine(); 3144 f.Print("Avg:"); 3145 for (unsigned ti = 0; ti < numThreadsTests; ti++) 3146 { 3147 PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), kFieldSize_CrcSpeed); 3148 } 3149 f.NewLine(); 3150 } 3151 return S_OK; 3152 } 3153 3154 bool use2Columns = false; 3155 3156 bool totalBenchMode = (method.MethodName.IsEqualTo_Ascii_NoCase("*")); 3157 bool onlyHashBench = false; 3158 if (method.MethodName.IsEqualTo_Ascii_NoCase("hash")) 3159 { 3160 onlyHashBench = true; 3161 totalBenchMode = true; 3162 } 3163 3164 // ---------- Threads loop ---------- 3165 for (unsigned threadsPassIndex = 0; threadsPassIndex < 3; threadsPassIndex++) 3166 { 3167 3168 UInt32 numThreads = numThreadsSpecified; 3169 3170 if (!multiThreadTests) 3171 { 3172 if (threadsPassIndex != 0) 3173 break; 3174 } 3175 else 3176 { 3177 numThreads = 1; 3178 if (threadsPassIndex != 0) 3179 { 3180 if (numCPUs < 2) 3181 break; 3182 numThreads = numCPUs; 3183 if (threadsPassIndex == 1) 3184 { 3185 if (numCPUs >= 4) 3186 numThreads = numCPUs / 2; 3187 } 3188 else if (numCPUs < 4) 3189 break; 3190 } 3191 } 3192 3193 CBenchCallbackToPrint callback; 3194 callback.Init(); 3195 callback._file = printCallback; 3196 3197 IBenchPrintCallback &f = *printCallback; 3198 3199 if (threadsPassIndex > 0) 3200 { 3201 f.NewLine(); 3202 f.NewLine(); 3203 } 3204 3205 if (!dictIsDefined) 3206 { 3207 const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25); 3208 unsigned dicSizeLog = dicSizeLog_Main; 3209 3210 #ifdef UNDER_CE 3211 dicSizeLog = (UInt64)1 << 20; 3212 #endif 3213 3214 if (ramSize_Defined) 3215 for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) 3216 if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize) 3217 break; 3218 3219 dict = (UInt32)1 << dicSizeLog; 3220 3221 if (totalBenchMode && dicSizeLog != dicSizeLog_Main) 3222 { 3223 f.Print("Dictionary reduced to: "); 3224 PrintNumber(f, dicSizeLog, 1); 3225 f.NewLine(); 3226 } 3227 } 3228 3229 PrintRequirements(f, "usage:", true, GetBenchMemoryUsage(numThreads, dict, totalBenchMode), "Benchmark threads: ", numThreads); 3230 f.NewLine(); 3231 3232 f.NewLine(); 3233 3234 if (totalBenchMode) 3235 { 3236 callback.NameFieldSize = kFieldSize_Name; 3237 use2Columns = false; 3238 } 3239 else 3240 { 3241 callback.NameFieldSize = kFieldSize_SmallName; 3242 use2Columns = true; 3243 } 3244 callback.Use2Columns = use2Columns; 3245 3246 bool showFreq = false; 3247 UInt64 cpuFreq = 0; 3248 3249 if (totalBenchMode) 3250 { 3251 showFreq = true; 3252 } 3253 3254 unsigned fileldSize = kFieldSize_TotalSize; 3255 if (showFreq) 3256 fileldSize += kFieldSize_EUAndEffec; 3257 3258 if (use2Columns) 3259 { 3260 PrintSpaces(f, callback.NameFieldSize); 3261 PrintRight(f, "Compressing", fileldSize); 3262 f.Print(kSep); 3263 PrintRight(f, "Decompressing", fileldSize); 3264 } 3265 f.NewLine(); 3266 PrintLeft(f, totalBenchMode ? "Method" : "Dict", callback.NameFieldSize); 3267 3268 int j; 3269 3270 for (j = 0; j < 2; j++) 3271 { 3272 PrintRight(f, "Speed", kFieldSize_Speed + 1); 3273 PrintRight(f, "Usage", kFieldSize_Usage + 1); 3274 PrintRight(f, "R/U", kFieldSize_RU + 1); 3275 PrintRight(f, "Rating", kFieldSize_Rating + 1); 3276 if (showFreq) 3277 { 3278 PrintRight(f, "E/U", kFieldSize_EU + 1); 3279 PrintRight(f, "Effec", kFieldSize_Effec + 1); 3280 } 3281 if (!use2Columns) 3282 break; 3283 if (j == 0) 3284 f.Print(kSep); 3285 } 3286 3287 f.NewLine(); 3288 PrintSpaces(f, callback.NameFieldSize); 3289 3290 for (j = 0; j < 2; j++) 3291 { 3292 PrintRight(f, "KiB/s", kFieldSize_Speed + 1); 3293 PrintRight(f, "%", kFieldSize_Usage + 1); 3294 PrintRight(f, "MIPS", kFieldSize_RU + 1); 3295 PrintRight(f, "MIPS", kFieldSize_Rating + 1); 3296 if (showFreq) 3297 { 3298 PrintRight(f, "%", kFieldSize_EU + 1); 3299 PrintRight(f, "%", kFieldSize_Effec + 1); 3300 } 3301 if (!use2Columns) 3302 break; 3303 if (j == 0) 3304 f.Print(kSep); 3305 } 3306 3307 f.NewLine(); 3308 f.NewLine(); 3309 3310 if (specifiedFreq != 0) 3311 cpuFreq = specifiedFreq; 3312 3313 3314 if (totalBenchMode) 3315 { 3316 for (UInt32 i = 0; i < numIterations; i++) 3317 { 3318 if (i != 0) 3319 printCallback->NewLine(); 3320 HRESULT res; 3321 3322 const unsigned kNumCpuTests = 3; 3323 for (unsigned freqTest = 0; freqTest < kNumCpuTests; freqTest++) 3324 { 3325 PrintLeft(f, "CPU", kFieldSize_Name); 3326 UInt32 resVal; 3327 RINOK(FreqBench(complexInCommands, numThreads, printCallback, 3328 (freqTest == kNumCpuTests - 1 || specifiedFreq != 0), // showFreq 3329 specifiedFreq, 3330 cpuFreq, resVal)); 3331 callback.NewLine(); 3332 3333 if (specifiedFreq != 0) 3334 cpuFreq = specifiedFreq; 3335 3336 if (freqTest == kNumCpuTests - 1) 3337 SetComplexCommands(testTime, specifiedFreq != 0, cpuFreq, complexInCommands); 3338 } 3339 callback.NewLine(); 3340 3341 callback.SetFreq(true, cpuFreq); 3342 3343 if (!onlyHashBench) 3344 { 3345 res = TotalBench(EXTERNAL_CODECS_LOC_VARS 3346 complexInCommands, numThreads, 3347 dictIsDefined || fileDataBuffer.Buffer, // forceUnpackSize 3348 fileDataBuffer.Buffer ? fileDataBuffer.BufferSize : dict, 3349 fileDataBuffer.Buffer, 3350 printCallback, &callback); 3351 RINOK(res); 3352 } 3353 3354 res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS complexInCommands, numThreads, 3355 1 << kNumHashDictBits, printCallback, &callback, &callback.EncodeRes, true, cpuFreq); 3356 RINOK(res); 3357 3358 callback.NewLine(); 3359 { 3360 PrintLeft(f, "CPU", kFieldSize_Name); 3361 UInt32 resVal; 3362 UInt64 cpuFreqLastTemp = cpuFreq; 3363 RINOK(FreqBench(complexInCommands, numThreads, printCallback, 3364 specifiedFreq != 0, // showFreq 3365 specifiedFreq, 3366 cpuFreqLastTemp, resVal)); 3367 callback.NewLine(); 3368 } 3369 } 3370 } 3371 else 3372 { 3373 bool needSetComplexity = true; 3374 if (!methodName.IsEqualTo_Ascii_NoCase("LZMA")) 3375 { 3376 unsigned i; 3377 for (i = 0; i < ARRAY_SIZE(g_Bench); i++) 3378 { 3379 const CBenchMethod &h = g_Bench[i]; 3380 AString benchMethod (h.Name); 3381 AString benchProps; 3382 int propPos = benchMethod.Find(':'); 3383 if (propPos >= 0) 3384 { 3385 benchProps = benchMethod.Ptr(propPos + 1); 3386 benchMethod.DeleteFrom(propPos); 3387 } 3388 3389 if (AreSameMethodNames(benchMethod, methodName)) 3390 { 3391 if (benchProps.IsEmpty() 3392 || benchProps == "x5" && method.PropsString.IsEmpty() 3393 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps)) 3394 { 3395 callback.BenchProps.EncComplex = h.EncComplex; 3396 callback.BenchProps.DecComplexCompr = h.DecComplexCompr; 3397 callback.BenchProps.DecComplexUnc = h.DecComplexUnc;; 3398 needSetComplexity = false; 3399 break; 3400 } 3401 } 3402 } 3403 if (i == ARRAY_SIZE(g_Bench)) 3404 return E_NOTIMPL; 3405 } 3406 if (needSetComplexity) 3407 callback.BenchProps.SetLzmaCompexity(); 3408 3409 for (unsigned i = 0; i < numIterations; i++) 3410 { 3411 const unsigned kStartDicLog = 22; 3412 unsigned pow = (dict < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog; 3413 if (!multiDict) 3414 pow = 31; 3415 while (((UInt32)1 << pow) > dict && pow > 0) 3416 pow--; 3417 for (; ((UInt32)1 << pow) <= dict; pow++) 3418 { 3419 char s[16]; 3420 ConvertUInt32ToString(pow, s); 3421 unsigned pos = MyStringLen(s); 3422 s[pos++] = ':'; 3423 s[pos] = 0; 3424 PrintLeft(f, s, kFieldSize_SmallName); 3425 callback.DictSize = (UInt32)1 << pow; 3426 3427 COneMethodInfo method2 = method; 3428 3429 if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA")) 3430 { 3431 // We add dictionary size property. 3432 // method2 can have two different dictionary size properties. 3433 // And last property is main. 3434 NCOM::CPropVariant propVariant = (UInt32)pow; 3435 RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant)); 3436 } 3437 3438 size_t uncompressedDataSize; 3439 if (fileDataBuffer.Buffer) 3440 { 3441 uncompressedDataSize = fileDataBuffer.BufferSize; 3442 } 3443 else 3444 { 3445 uncompressedDataSize = callback.DictSize; 3446 if (uncompressedDataSize >= (1 << 18)) 3447 uncompressedDataSize += kAdditionalSize; 3448 } 3449 3450 HRESULT res = MethodBench( 3451 EXTERNAL_CODECS_LOC_VARS 3452 complexInCommands, 3453 true, numThreads, 3454 method2, 3455 uncompressedDataSize, fileDataBuffer.Buffer, 3456 kOldLzmaDictBits, printCallback, &callback, &callback.BenchProps); 3457 f.NewLine(); 3458 RINOK(res); 3459 if (!multiDict) 3460 break; 3461 } 3462 } 3463 } 3464 3465 PrintChars(f, '-', callback.NameFieldSize + fileldSize); 3466 3467 if (use2Columns) 3468 { 3469 f.Print(kSep); 3470 PrintChars(f, '-', fileldSize); 3471 } 3472 3473 f.NewLine(); 3474 3475 if (use2Columns) 3476 { 3477 PrintLeft(f, "Avr:", callback.NameFieldSize); 3478 PrintTotals(f, showFreq, cpuFreq, callback.EncodeRes); 3479 f.Print(kSep); 3480 PrintTotals(f, showFreq, cpuFreq, callback.DecodeRes); 3481 f.NewLine(); 3482 } 3483 3484 PrintLeft(f, "Tot:", callback.NameFieldSize); 3485 CTotalBenchRes midRes; 3486 midRes.SetSum(callback.EncodeRes, callback.DecodeRes); 3487 PrintTotals(f, showFreq, cpuFreq, midRes); 3488 f.NewLine(); 3489 3490 } 3491 return S_OK; 3492 }